Nest 实现 SSE

原帖

服务端实时推送数据,除了用 WebSocket 外,还可以用 HTTP 的 <font style="color:rgb(37, 41, 51);">Server Send Event</font> (SSE)。

只要 http 返回 Content-Type 为 text/event-stream 的 header,就可以通过 stream 的方式多次返回消息了。它传输的是 json 格式的内容,可以用来传输文本或者二进制内容。

一次请求,随后就是多次响应,简单又直接,而且连接断了,浏览器会自动重连。而 WebSocket 需要手动重连。

控制台中也能看到清晰的消息列表:


后端

nest 后端使用 <font style="color:rgb(37, 41, 51);">@Sse</font> 然后返回 Observe 对象就可以了。内部可以通过 observer.next 随时返回数据

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
  @Sse('stream')
stream() {
return new Observable<{ data: { msg: string } }>((observer) => {
observer.next({ data: { msg: 'aaa' } });
setTimeout(() => {
observer.next({ data: { msg: 'bbb' } });
}, 2000);
setTimeout(() => {
observer.next({ data: { msg: 'ccc' } });
}, 4000);
});
}

@Sse('stream2')
stream2() {
// 只要修改 log 便会触发SSE消息推送。
const childProcess = exec('tail -f ./log');
return new Observable((observer) => {
childProcess.stdout.on('data', (m) => {
observer.next({ data: { msg: m.toString() } });
});
});
}

@Sse('stream3')
stream3() {
return new Observable((observer) => {
const json = readFileSync('./package.json').toJSON();
observer.next({ data: { msg: json }});
});
}

前端

前端使用 <font style="color:rgb(37, 41, 51);">EventSource</font> 的 onmessage 来接收消息。

1
2
3
4
const eventSource = new EventSource("http://localhost:3000/stream");
eventSource.onmessage = ({ data }) => {
console.log("New message", JSON.parse(data));
};

这个 api 的兼容性很好,除了 ie 外可以放心的用。

它的应用场景有很多,比如站内信、构建日志实时展示、chatgpt 的消息返回等

再遇到需要消息推送的场景,不要直接 WebSocket 了,也许 Server Send Event 更合适捏


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!