简介
Server-sent Events (SSE) 是一种基于 HTTP 的单向数据流协议,它通过浏览器与服务器之间的长时连接,实现了服务端实时向客户端推送数据的能力。不同于 WebSocket,SSE 仅支持服务器向客户端的单向数据传输,不支持客户端向服务器发送消息。
SSE 可以用于实现许多实时应用场景,如实时聊天、股票行情、运动比赛等。本文将探讨 SSE 的优化方法,让我们的 SSE 式应用更加健壮、稳定。
SSE 的特点
SSE 的主要特点如下:
- 基于 HTTP,支持跨域传输。
- 单向数据传输,仅支持服务器向客户端发送数据。
- 支持自动重连,当连接中断时自动尝试重新连接。
- 支持事件流式传输,并在传输过程中可以动态更新事件名、事件 ID 等元数据信息。
SSE 的工作原理
与 WebSocket 不同,SSE 是基于 HTTP 长连接实现数据的传输的。连接的建立也与普通的 HTTP 连接类似,客户端通过创建一个新的 EventSource 对象来建立与服务端的连接:
const eventSource = new EventSource('/stream');
其中,/stream 是服务端提供的 SSE 接口。
服务端通过设置 HTTP 响应头,告知浏览器这是一条 SSE 数据流。下面是一个示例的响应头:
Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive
其中,Content-Type 告知浏览器响应内容类型,Cache-Control 禁用浏览器缓存,Connection 保持连接不关闭。
服务端发送的数据通过一些特殊的格式进行传输,格式如下:
event: <事件名称> id: <事件 ID> data: <事件数据>
其中,"event" 和 "id" 是可选的元数据信息,可以不设置。"data" 则是事件的主体内容,每行仅能包含一条事件。
当服务端发送数据时,浏览器会触发一个 message 事件,我们可以通过监听这个事件来处理服务端发送的事件数据:
eventSource.addEventListener('message', function(event) { const data = JSON.parse(event.data); console.log(data); });
SSE 的优化方法
重试机制
由于 SSE 是建立在 HTTP 长连接之上,所以连接在传输过程中可能随时中断。这时,浏览器会自动尝试重新连接。但是这个重试间隔时间可能比较长,这对实时应用场景来说是不可接受的。
我们可以通过在服务端设置 Retry-Time 来控制浏览器进行重连的时间间隔,如下:
retry: <重试时间>
重试时间以毫秒为单位。在服务端发送 Retry-Time 头字段后,如果连接断开,浏览器将按照这个时间间隔自动尝试重新连接。
丢失事件恢复
在传输数据流的过程中,如果某条事件的数据传输失败,它不会触发 message 事件,这样就会导致事件的丢失。对于对数据实时性要求高的应用场景来说,这是不可接受的。
我们需要一种机制来保证事件传输的可靠性。以 Vue.js 为例,在 data 接口中提供了一个 Last-Event-ID 的参数,用于标识接收到的最后一个事件 ID。服务端可以通过 Last-Event-ID 这个参数来保证事件序列不被破坏。
客户端发送 SSE 请求时,可以通过设置 withCredentials 参数为 true 来使跨域请求可以携带 cookie 等身份信息:
const eventSource = new EventSource('/stream', { withCredentials: true });
在服务端响应数据时,需要加入 Last-Event-ID 参数:
id: <事件 ID>\n
在客户端接收数据时,需要先根据 Last-Event-ID 进行事件序列的补偿,保证事件不丢失:
-- -------------------- ---- ------- --- ----------- - ----------------------------------- -- ----- --------------------- - -------- ------- - ----- ---- - ----------- ----- ------- - ------------------------------ -- -- ----------- ------- ----------------------- -- ------------- -- ------------ --- --------- - ----------- - -------- ----------------------------------- --------- -- ------- -- - - ---- - -- --------------- --------------------------------------- -------------------- ---------- - --
在每次传输完成后,客户端需要将最后一个事件 ID 存储到本地,以便下一次传输时进行补偿。
事件标识机制
当我们在实现 SSE 应用时,可能会遇到需求动态添加、删除事件监听函数的情况。如果在仅通过事件名称匹配时,没有办法精准地定位到某个特定事件所对应的所有监听函数。
我们可以通过动态更新事件的元数据信息来对每个事件进行标识。例如,我们可以通过修改事件名及其对应的 ID 来标识事件。对于需要动态添加、删除监听函数的场景,我们只需根据事件名称及其 ID 进行监听即可。
资源优化
由于 SSE 是基于 HTTP 长连接实现的,因此它是非常耗费资源的。为了减少服务器负载及网络带宽的消耗,我们可以通过控制每次传输事件的大小、事件的传输频率等方法来减小 SSE 请求的资源消耗。
总结
本文介绍了 SSE 的特点及工作原理,并针对 SSE 应用中的一些常见问题,提出了相应的优化措施。通过这些优化方法,可以使 SSE 在实际应用中更为稳定、高效。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6649ae44d3423812e4896a63