GPT聊天实现(一)——Server-Sent Events和EventSource

345 阅读2分钟

最近在做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的原理和实现方式。

参考资料: