Loading... SSE 是基于 http 协议的服务器推送技术,数据只能从服务端到客户端。服务端把序列化后的数据发送给客户端,整个过程持续不断直至连接关闭 #### WebSocket 对比 SSE * SSE 和轮询使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议 * SSE 属于轻量级的 WebSocket,使用简单;WebSocket 使用相对复杂,轮询使用简单 * SSE 默认支持断线重连,WebSocket 需要自己实现断线重连 * SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据 * SSE 支持自定义发送的消息类型 * WebSocket 支持双向推送消息,SSE 是单向的 * 轮询性能开销大、轮询时间久导致客户端及时更新数据 #### node后端代码示例 ```js app.post('/sse', (req, res) => { res.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }) res.flushHeaders() setInterval(() => { res.write(`event: message\n`); res.write(`data: ${JSON.stringify({})}\n\n`); }, 1000) }) ``` 这段代码创建了一个路由,当客户端请求`/sse`时,将返回一个SSE事件流。我们将设置`Content-Type`头为`text/event-stream`,这是SSE所需的。我们还将设置`Cache-Control`头为`no-cache`,这将防止客户端缓存事件流。 在事件流的头部,我们将使用`Connection: keep-alive`,这将保持连接打开,直到服务器明确地关闭连接。 我们还使用了`res.flushHeaders()`来立即发送事件流的头部。这是必需的,因为浏览器将等待完整的HTTP头部才能开始处理数据。 在这里,我们使用了`setInterval()`来模拟每秒钟向客户端发送一次事件。在实际应用中,您可以使用数据库更改或其他技术来推送实时更新比如`rxjs`。 每次我们使用`res.write()`方法将新的数据发送到客户端。我们在数据前添加了`data:`前缀,这是SSE事件流所需的。最后,我们在每个事件之间添加了一个空行`\n\n`,这是SSE事件流规范要求的,以便客户端可以正确解析事件流。 我们用`\n`来分隔每一行数据,用`\n\n`来分隔每一个事件。每一个事件中包含事件的type和事件的data,分别用两行来描述。比如上面是返回来一个message事件(若不指定事件类型,则默认message)。 #### 前端原生代码示例 ```js const eventSSE = new EventSource('url') eventSSE.onopen = function() { console.log("Connection to server opened.") } eventSSE.onmessage = function(e) { console.log(e.data) } eventSSE.onerror = function() { console.log("EventSource failed.") } eventSSE.addEventListener("customize", function(event) { // 服务器可以与浏览器约定自定义事件。这种情况下,发送回来的数据不会触发message事件。 }) cloneSSE = function() { eventSSE.close() } ``` #### event-source-polyfill 库 `SSE` 不能通过 `headers` 传递 `Authorization token`。虽然可以把 token 放在 url 上解决不能传 `token` 的问题,但是会引发 `token` 安全隐患。可以通过此库解决。 ```js import { EventSourcePolyfill } from "event-source-polyfill" const eventSSE = new EventSourcePolyfill(url, { headers: { authorization: "Bearer token" } }) eventSSE.addEventListener("message", (event) => { console.log("receiving data from server:", JSON.parse(event.data)) }) ``` #### 不足之处 `event-source-polyfill` 只是在一定的程度上解决了 `Authorization token` 的问题,但它们也存在问题。这个库提供的 `close` 方法只能关闭处于 `pending` 状态的 SSE 连接,因为 fetch 一旦从 `pending` 变为 `resolved` 或 `reject`, 其结果无法改变。当频繁的断开 SSE 连接和建立新 SSE 连接时,旧的 SSE 连接实际上并没有关闭,系统里会存在多个 SSE 连接,这样会带来很大的性能开销 #### 参考链接 [深入浅出 Server-sent events 技术](https://segmentfault.com/a/1190000043392930) [实时通信变得简单](https://juejin.cn/post/7205412097953808445) 最后修改:2023 年 04 月 20 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏