背景
我们在使用 GPT 或者 套壳 GPT 时,会发现对话的文字是一段一段展示出来的,而不是一次性,观察接口的 Content-Type
可以看到,使用的是 text/event-stream;charset=UTF-8
, 也就是 Server-Sent Events
服务端推送 (下文简称 SSE
), 它和 WebSocket
不同,是单向的服务器推送,类似 HTTP 2
的 Server Push
, 这篇文章就让我们来简单了解下 SSE
.
什么是 Server-Sent Events
Server-Sent Events (SSE) 本质上就是一个 HTTP
接口,区别于常见的 json
消息体,Content-Type: application/json; charset=utf-8
, 它的类型为 Content-Type: text/event-stream;charset=UTF-8
, 在调试窗口的 EventStream
中可以看到:
标准报文体 如下:
1 | id: xxx |
客户端如何发起 SSE 请求
既然也是 HTTP
接口,那么如何发起请求呢?不同于 XMLHttpRequest
或者 fetch
, 浏览器提供 [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)
API 进行 SSE
的请求
MDN 示例
1 | const sse = new EventSource("/api/v1/sse"); |
服务器如何接受 SSE 请求
客户端发起 SSE
请求后,各种套壳 GPT 应用肯定要 调用 GPT 3.5 API (访问自研大模型进行取数) , 这里以 Node.js
为例
首先使用 express
搭一个服务
1 | const express = require('express'); |
然后声明一个 /sse
GET 请求
1 | const { Transform } = require('node:stream'); |
数据流
当接收到请求后,使用 Node.js
的 [Transform](https://nodejs.org/api/stream.html#class-streamwritable:~:text=event%20is%20emitted.-,Class%3A%20stream.Transform,-%23)
流,对数据进行转换
在 Node.js 中,标准的输入输出流分别为:
- 输入流
- 输出流
- 错误流
而流又分为:
- 可读流 (Readable)
- 可写流 (Writable)
- 双工流 (Duplex)
- 转换流 (Transform)
其中双工流和转换流都是可读可写的。
输入流 (Readable)
1 | process.stdin |
输出流 (Writable)
1 | process.stdout |
错误流 (Writable)
1 | process.stderr |
写入请求头
首先写入 text/event-stream
的 Content-Type
1 | res.writeHead(200, { |
使用转换流将内容转成 SSE 的消息体格式
1 | const { Transform } = require('node:stream'); |
完整代码如下:
1 | const { Transform } = require('node:stream'); |
上诉的步骤相对来说比较繁琐,可以也可以使用 ssestream
这个库
1 | const SseStream = require('ssestream').default; |
效果如图,可以看到每秒钟会收到服务器推送的消息,查看 Demo 完整代码