前言
关于最近大火的 chatGPT 相信大家对它也很感兴趣吧,是不是迫不及待地想把它接入到自己的项目中玩一玩啦 ?
那么在 chatGPT 接入的过程中需要注意些什么呢?
众所周知 chatGPT 通过流式传输实现了打字机的效果,服务器将实时生成的事件或消息推送给客户端,以实现实时的交互和内容更新。
这种事件推送流与 ChatGPT 模型相结合,使模型能够根据生成的事件动态地响应并生成新的内容,以便客户端可以立即作出响应活展示新的内容。
那么客户端与服务端在传输流式数据时该如何建立持久连接以便客户端接收 ChatGPT 生成的结果呢?
HTTP 服务器推送
HTTP 的服务器推送,也称为 HTTP 推送或 HTTP 长轮询,是一种服务器向客户端主动发送数据的机制。相对传统的 HTTP 通信是由客户端向服务器发送请求,然后服务器返回响应的请求-响应模型。
而HTTP服务器推送则是服务器在没有明确的请求的情况下主动向客户端发送数据。
在HTTP服务器推送中,客户端与服务器建立一种持久连接,服务器可以在任何时候向客户端发送数据,而不需要等待客户端发送请求。
这种机制可以用于实现数据的实时更新和即时通信,使得服务器可以向客户端即时推送新的内容和事件。
HTTP服务器推送的实现方式有多种:
- 长轮询(Long Polling):客户端发送一个长期挂起的请求到服务器,服务器在有新数据时才返回响应,否则一直等待直到有新数据到达。
- Server-Sent Events(SSE):使用SSE技术,服务器可以通过单向的持久连接向客户端发送实时事件和数据。服务器发送的数据被封装为一系列的事件流,客户端通过监听这些事件流来接收数据。
- WebSocket:WebSocket是一种全双工的通信协议,允许在客户端和服务器之间建立双向的实时通信连接。服务器和客户端可以随时发送消息给对方,以便实现数据的双向通信。
这些机制都旨在克服传统的请求-响应模型的限制,允许服务器主动向客户端推送数据,以实现数据传输的实时性和即时性。
HTTP服务器推送在实时通信、实时数据展示、实时协作等场景中非常有用,如聊天应用、股票市场数据更新、实时新闻推送等。
它可以提供更好的用户体验,减少了客户端频繁请求的开销,并允许服务器主动推送重要的信息给客户端。
什么是SSE?
SSE(Server-Sent Events)是一种基于 HTTP 的服务器推送技术,用于实现服务器向客户端单向发送实时事件和数据的通信机制。
与传统的请求-响应模型不同,SSE 允许服务器主动发送数据给客户端,从而实现实时更新和内容推送。
SSE 通信的特点包括:
- 单向通信:SSE 是服务器向客户端的单向通信,客户端通过与服务器建立持久连接,接收服务器主动推送的事件和数据。
- 实时更新:SSE 可以实时地将服务器端的数据和事件传送给客户端,从而实现实时更新和通知。
- SSE 基于 HTTP 协议:使用标准的 HTTP 连接,不需要额外的握手或协议切换。
- 自动重连:SSE 具备自动重连机制,当连接中断时,客户端会自动尝试重新连接到服务器,以保持持久连接。
我们可以用 node 搭建一个后端服务,以提供接口
// 创建了一个HTTP服务器
const http = require('http');
http.createServer((req, res) => {
// 设置允许跨域请求的头部字段
res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有域名的请求
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); // 允许的HTTP方法
res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 允许的请求头
// 设置响应头
res.writeHead(200, {
'Content-Type': 'text/event-stream', // 指定响应类型为 text/event-stream 向客户端推送事件流
'Cache-Control': 'no-cache', // 客户端不应缓存响应,每次请求都需要从服务器获取最新的数据。
'Connection': 'keep-alive' // 客户端与服务器保持持久的连接
});
const sendEvent = (data) => {
// 将响应的内容写入到响应流中,每次传输的数据以 data: 字段开头,\n\n 结尾进行发送。
res.write(`data: ${data}\n\n`); // \n\n表示一个换行,用于分隔不同的事件
};
// 每秒钟发送一个事件
setInterval(() => {
sendEvent(new Date().toISOString());
}, 1000);
}).listen(3000);
在 node 环境中创建一个 HTTP 服务器,设置请求头允许跨域请求的发生,并设置响应头将其标识 SSE 通信,以便与客户端建立持久的连接传输数据流。
请注意,对于SSE 流式传输,保持长连接是非常重要的,因为它需要服务器不断地向客户端发送事件数据。因此,在使用 SSE 时,配置请求头为 Connection: keep-alive 是一个常见的做法,以确保持久连接的实现。
在客户端需要我们主动建立 SSE 连接
const eventSource = new EventSource('http://localhost:3000');
eventSource.onmessage = (event) => {
console.log('Received event:', event.data);
};
使用 EventSource 对象创建了一个 SSE 连接,并指定了服务端的URL。
通过监听 onmessage 事件,我们可以接收并处理从服务器推送过来的事件数据。
当运行以上代码时,客户端将会每秒钟接收到一个事件,其中包含当前时间戳的数据。
EventSource 的使用
客户端创建 EventSource 对象,监听对象,在与客户端建立连接后,服务端使用 response.write() 方法向客户端发送事件数据。
客户端通过监听 EventSource 对象的事件流对接收到的数据进行处理
// 使用 EventSource 建立连接
let eventSource = new EventSource('http://xxx.xxx/sse/' + id')
// 监听连接完成
eventSource.onopen = function(event){
console.log(event)
}
// 接收服务端传输的数据流
eventSource.onmessage= function(event){
console.log(event.data)
}
// 监听错误事件
eventSource.onerror= function(event){
console.log(event.readyState)
}
// 断开SSE通信
eventSource.close();
EventSource 有三个默认的事件,分别是:
- open:在连接打开时被调用。
- message:收到一个没有 event 属性的消息时被调用。
- error:当发生错误时被调用。
一个方法:
- close:关闭与服务器的连接。
两个只读属性:
- readyState:代表连接状态。可能值是CONNECTING (0), OPEN (1), 或者 CLOSED (2)。
- url:代表连接的 URL。
// 每一个事件对象都有都有 readyState 表示连接状态
event.readyState == EventSource.CONNECTING //0 连接尚未建立,或已关闭且客户端正在重新连接
event.readyState == EventSource.OPEN //1 客户端有一个打开的连接并在接收到事件时处理它们
event.readyState == EventSource.CLOSED //2 连接未打开,并且客户端未尝试重新连接,要么出现致命错误,要么调用了 close() 方法
如果与服务器的连接丢失或失败,EventSource 会自动尝试重新连接。
注意:浏览器对 EventSource 的重新连接行为有一些限制和策略,以确保不会产生过多的连接尝试。
在实际应用中,可以根据需要定义不同的事件类型和数据格式,并使用 SSE 来实现实时更新和推送内容,例如实时聊天、实时数据展示等场景。
WebSocket 和 SSE 的区别
当涉及到实时通信和服务器推送时,WebSocket 和SSE(Server-Sent Events)是两种常见的技术选择。以下是WebSocket 和 SSE 之间的一些区别:
WebSocket | SSE | |
---|---|---|
协议 | 使用 WebSocket 协议进行通信 | 使用 HTTP 协议进行通信 |
双向通信 | 支持双向通信,客户端和服务器都可以发送消息 | 仅服务器向客户端推送消息 |
持久连接 | 是,建立长期的持久连接 | 是,建立长期的持久连接 |
通信方式 | 使用消息(Message)进行通信 | 使用事件(Event)进行通信 |
数据格式 | 支持传输二进制数据和文本数据 | 仅支持传输文本数据 |
兼容性 | 广泛支持,包括现代浏览器和服务器环境 | 广泛支持,但在某些旧浏览器上可能不支持 |
扩展性 | 可以实现自定义的协议和功能 | 功能相对较简单,无法自定义协议 |
客户端实现 | 需要使用 WebSocket API | 可以使用浏览器的原生 EventSource API |
服务器实现 | 需要使用 WebSocket 服务器实现 | 可以使用普通的 HTTP 服务器实现 |
总体而言,WebSocket 和 SSE 都提供了一种实现实时通信和服务器推送的方法,但在某些方面存在一些区别。
- WebSocket 适合双向通信和传输二进制数据,支持自定义协议和功能,但需要 WebSocket 服务器实现。
- SSE 仅支持服务器向客户端推送消息,仅传输文本数据,但可以使用标准的 HTTP 服务器实现,并且在浏览器中有更广泛的兼容性。
选择 WebSocket还是SSE 取决于您的具体需求和技术栈。如果您需要双向通信和传输二进制数据,或者需要自定义协议和功能,那么 WebSocket 可能是更好的选择。如果您只需要服务器向客户端推送消息,并且更关注兼容性和简单性,那么SSE可能是更适合的选项。
总结
SSE 的优势在于它的简单性和轻量性,在服务器和客户端之间建立持续稳定的连接,实现服务器向客户端单向推送数据。与 WebSockets相比,SSE 只需要使用标准的HTTP协议,无需进行双向通信,因此实现起来更加简单,并对服务器资源的消耗也低。
相比传统的请求-响应模式,SSE 让聊天对话更加流畅,无需频繁发送请求,而是通过持续的推送来获取响应。
甚至在 ChatGPT 中,可以通过 SSE 实现流式应答,服务器不断向客户端推送生成的文本数据,使得聊天对话可以实时地显示在客户端上实现打印机的效果。
希望通过本文大家能对 SSE 能有一定的了解,在今后的开发中能派上用场有所帮助?。