Linking

Capturing Life & Tech

  • 主页
  • 随笔
  • 关于我
所有文章 外链

Linking

Capturing Life & Tech

  • 主页
  • 随笔
  • 关于我

server-sent events

阅读数:次 2022-11-28
字数统计: 652字   |   阅读时长≈ 4分

Basic, Intro

Websockets and SSE (Server Sent Events) are both capable of pushing data to browsers.

Websockets connections can both send data to the browser and receive data from the browser.

SSE connections can only push data to the browser.

SSE is Simpler, case by case.

Backend

SseEmitter (Spring Framework 6.0.2 API)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* get realtime state by SSE
* use redis as mq, get realtime state
* continue send data to frontend if there has data in redis
*
* @param id id
*/
@GetMapping(value = "/getRunStatusById", produces = "text/event-stream;charset=UTF-8")
public SseEmitter getRunStatusById(@RequestParam("id") long id) {
final long userId = getUserId();
SseEmitter emitter = new SseEmitter(0L); //0 means no limit timemout
emitter.onError(throwable -> logger.error("emitter-error:" + throwable.getMessage()));
emitter.onCompletion(() -> logger.info("emitter run onCompletion."));
emitter.onTimeout(() -> {
logger.info("emitter timeout");
emitter.complete();
});

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
AtomicInteger eventId = new AtomicInteger(1);
executor.scheduleWithFixedDelay(() ->
{
try {
Set<String> zSetData = getTestDataFromRedis(userId, id);
if (zSetData == null || zSetData.size() == 0 || StringUtils.isEmpty(zSetData.stream().findFirst().orElse(""))) { //no data
SseEmitter.SseEventBuilder event = SseEmitter.event().data("notRun").id(String.valueOf(eventId));
emitter.send(event);
executor.shutdown();
emitter.complete();
} else { //if has data
SseEmitter.SseEventBuilder event = SseEmitter.event().data("running").id(String.valueOf(eventId));
emitter.send(event);
}
logger.info("emitter eventid: " + eventId);
eventId.getAndIncrement();
} catch (Exception ex) {
logger.error("getRunStatusById error: " + ex.getMessage(), ex);
emitter.completeWithError(ex);
executor.shutdown();
}
}, 0, 1, TimeUnit.SECONDS);

return emitter;
}
  • SseEmitter: one implement of sse
  • ScheduledExecutorService.scheduleWithFixedDelay: sent data with schedule delay, like use Scheduled annotation for a job, but job is not recomend

Frontend, with token for authorization

https://github.com/Yaffle/EventSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const createEventSource = url => {
const token = window.store.state.common.token
const eventSource = new EventSourcePolyfill(`${process.env.VUE_APP_BASE_URL}${url}`, {
headers: {
Authorization: `Bearer ${token}`,
withCredentials: true
}
})

eventSource.onopen = (event) => {
// console.log(event)
// console.log('event-source connect success,url:' + url)
}

eventSource.onmessage = event => {
console.log(event)
console.log('eventId'+event.lastEventId + ', data:' + event.data)
if(event.data.indexOf("notRun") > -1) {
console.log('notRun or end')
eventSource.close()
}
}

eventSource.onerror = (event) => {
console.log('network error or event end')
console.log(event)
console.log('readyState ' + event.target.readyState + '; error:' + event)
event.target.close()
}

return eventSource
}

nginx

It’s important to note that an EventSource requires an HTTP/1.1 server to work correctly. This is because, unlike XMLHttpRequest, an EventSource request is kept open indefinitely and therefore relies on features only present in HTTP/1.1, such as chunked encoding. In addition, the HTTP status code of the response must be 200 OK, or the connection will be closed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
worker_processes 4;
worker_connections 2048;
keepalive_timeout 65;

http {
server {
listen 80;

location /events/ {
proxy_pass http://backend_server;
proxy_set_header Connection '';
proxy_http_version 1.1; #important
proxy_set_header Host $host;
proxy_cache_bypass $http_pragma;
proxy_cache_revalidate on;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
}

Problems

1.timeout, responsebodyemitter has already completed

  • if sent data so many, set timeout to zero, but if unnecessary like send data one time, should use default timeout which is not set then, or set some timeout like new SseEmitter(1000L) which means 1s timeout

2.frontend error happen

  • frontend usecase is simple, mostly the error is some backend error

Reference

  • HTTP version should 1.1
  • server-sent_events.html
  • java source code of SseEmitterController
  • sse-with-timeout
  • Server-Sent Events Using Spring - DZone Java
  • Spring Server Sent Events - ResponseBodyEmitter is already set complete
  • Zero to Hero in Server Sent Events.
  • Quarkus-For-Spring-Developers-Red-Hat
  • 本文作者: Linking
  • 本文链接: https://linking.fun/2022/11/28/server-sent-events/
  • 版权声明: 版权所有,转载请注明出处!
  • sse
  • cs

扫一扫,分享到微信

排查并解决vpn访问内网的路由不对称问题
record something about disk common used
  1. 1. Basic, Intro
  2. 2. Backend
  3. 3. Frontend, with token for authorization
  4. 4. nginx
  5. 5. Problems
    1. 5.1. 1.timeout, responsebodyemitter has already completed
    2. 5.2. 2.frontend error happen
  6. 6. Reference
© 2015-2026 Linking
GitHub:hexo-theme-yilia-plus by Litten
本站总访问量次 | 本站访客数人
  • 所有文章
  • 外链

tag:

  • weather
  • 需求
  • essay
  • basketball
  • olympic
  • nginx
  • APPScan
  • SQl盲注
  • xss
  • Ajax
  • ajax
  • ai
  • agent
  • openclaw
  • ccf
  • Nginx
  • HTML5
  • html5
  • hmtl5
  • sse
  • JavaScriptCore
  • Oracle
  • operation
  • Linux
  • deploy
  • Mac Office
  • markdown
  • ListView
  • GridView
  • MySQL
  • 慢查询
  • mongodb
  • 转置
  • thought
  • network
  • ubuntu
  • NetworkManager
  • RFKill
  • Netplan
  • avatar
  • cocoa
  • blog
  • Gitalk
  • container
  • macvlan
  • docker
  • oracle
  • cookie
  • patch
  • gitea
  • git
  • iOS
  • https
  • 多线程
  • bundle
  • 兼容性
  • HTTP
  • 绘图
  • cs
  • java
  • 效率
  • 快捷键
  • route
  • nodejs
  • pip
  • arcgis
  • arcgis 建模
  • 标识
  • redis
  • read
  • bookList
  • running
  • showdoc
  • disk
  • unit-test
  • D.Wade
  • thoughts
  • duoduo
  • Python
  • python
  • tomcat
  • 读书节
  • session
  • jdk
  • war
  • 加班
  • Android onclick事件监听
  • 正则
  • 手机品牌匹配
  • ntp
  • OpenLayers
  • Geoserver
  • wechat
  • 微信公众号
  • 爬虫
  • WeChat
  • 张靓颖
  • 动漫
  • vpn
  • PPT
  • MarkDown
  • plan
  • 朱赟
  • 极客时间专栏
  • 极客邦
  • 模块化
  • MVC
  • excel
  • NBA
  • kobe
  • team
  • crawler
  • 进度条
  • ssl
  • book
  • anti-stealing-link
  • Agentic Engineering
  • Vibe Coding
  • Software 3.0
  • Andrej Karpathy
  • LLM
  • Programming

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia-plus根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • GitHub Trending
  • OpenAI ChatGPT
  • Gitee码云
  • 简书
  • CSDN