最近在做AI解读,想要做到ChatGPT回复消息的效果,边接收消息边显示,最开始想到的是Websocket服务端可以发送消息到客户端,后面查了一下通用的解决方式是使用Server-Sent Events来实现流传输数据,和Websocket相比SSE比较轻量化,使用简单,SSE是单向传输,只支持服务端发送消息到客户端,而Websocket是双向传输,这种聊天消息的流传输不需要双向,仅单向就足够了,创建SSE连接,接收消息,接收完成关系连接。
SSE
一种基于HTTP的传输协议,给客户端的信息是流数据,而不是一整个数据包。用流的方式给客户端发送信息,客户端可以接收一点显示一点。
EventSource
基于SSE的前端实现是EventSource。
一个
EventSource实例会对 HTTP 服务器开启一个持久化的连接,以text/event-stream格式发送事件,此连接会一直保持开启直到通过调用EventSource.close()关闭。
具体用法如下:
const evtSource = new EventSource('url');
evtSource.onopen((e) => {
// 建立连接处理
})
evtSource.onmessage((e) => {
// 接收消息处理
})
evtSource.onerror((e) => {
// 错误处理
})
// 事件还有另一种写法
evtSource.addEventListener("message", (e) => {
// 接收消息处理
});
evtSource.close() // 关闭连接
fetch-event-source
在用的过程中发现,EventSource不支持向接口传参,不符合我的使用场景,于是就找了fetch-event-source支持SSE,并且可以传参。
使用方法:
// BEFORE:
const sse = new EventSource('/api/sse');
sse.onmessage = (ev) => {
console.log(ev.data);
};
// AFTER:
import { fetchEventSource } from '@microsoft/fetch-event-source';
await fetchEventSource('/api/sse', {
onmessage(ev) {
console.log(ev.data);
}
});
传参:
const ctrl = new AbortController();
fetchEventSource('/api/sse', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
foo: 'bar'
}),
signal: ctrl.signal,
});
这样就可以给SSE的接口传参了。
欢迎大家一起讨论,下一篇更EventSource和fetch-event-source的原理和实现方式。
参考资料: