近些年来,前端开发逐渐从传统的基于请求响应的模式向场景比较特殊的长连接模式转变,Server-Sent Events(SSE)是一种非常适合此种情境的技术,它可以提供跨浏览器、跨设备的轻量级、双向通讯能力,是目前很多前端开发者经常使用的技术架构。本文将介绍常见问题及其解决方法,并给出相应的示例代码。
什么是 Server-Sent Events?
Server-Sent Events 是一种 HTML5 新特性,它允许客户端与服务器端建立一个不断传输的单向连接,在服务器端有更新时,能够自动地从服务器提供实时数据流。SSE 基于 HTTP 协议,但是与 WebSocket 协议不同,SSE 使用的是简单的文本和 HTTP 头信息,而不是二进制数据帧。
SSE 的优点
- 低延迟: 相较于传统的 Ajax 交互,SSE 的延迟非常小,可以将数据实时传输到客户端。
- 建立简单: SSE 不需要打开和维护长时间的连接,而且使用起来非常简单,只需要通过源生 JavaScript 创建一个 EventSource 实例,然后重写 onmessage 事件即可。
- 跨浏览器支持: 支持大部分主流浏览器,包括 Chrome、Firefox、Safari、Edge、IE 等,因为 SSE 只使用标准 HTTP,而不需要特殊的套接字或协议。
常见问题
问题一:SSE 连接中断后不能重新连接
由于 SSE 是基于 HTTP 协议的,因此我们可以使用 keep-alive 头以保证服务器连接持续开启,例如:
HTTP/1.1 200 OK Content-Type: text/event-stream; charset=utf-8 Cache-Control: no-cache Connection: keep-alive
在 keep-alive 的情况下,服务器在 SSE 连接断开后会继续保持连接,直到超时或者关闭连接。这样一来,我们的客户端能够保证获得 SSE 事件的能力,并且在网络故障或连接出错时更有弹性。
同时,如果我们发现连接失败或中断,我们可以通过如下代码来重新连接 SSE:
// javascriptcn.com 代码示例 var source = new EventSource('/events'); source.onerror = function(e) { if (this.readyState == EventSource.CONNECTING) { console.log("连接失败"); } }; source.onopen = function(e) { console.log("连接成功"); };
问题二:SSE 的定时器导致内存泄漏
当我们使用 SSE 定时器来推送事件到客户端时,需要特别注意内存泄漏问题。这是因为 SSE 的 EventSource 对象缓存了所有已经处理过的事件回调函数,如果我们不及时清理它们,会导致内存逐渐增加。
为了解决这个问题,我们可以直接重写 onmessage 方法,避免通过 addEventListener 方法来添加回调。这样,每当事件传递进来时,就只有一次 function 调用,并且不会将新的函数添加到缓存中,减少了内存占用。
var source = new EventSource('/events'); source.onmessage = function(e) { console.log(e.data); };
问题三:SSE 事件数据过大导致发送失败
由于 SSE 的长连接模型,如果服务器发送的事件数据过大,会导致连接超时或者一直保持在等待状态。因此,在处理 SSE 时,通常我们需要把事件分为多个小块来发送,同时客户端也需要分批处理。
例如,我们可以将分块操作交给服务器上的数据操作类来处理:
// javascriptcn.com 代码示例 header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); $interval = 1; while(true) { $data = getData(); foreach ($data as $payload) { echo "data: {$payload}\n\n"; ob_flush(); flush(); sleep($interval); } }
客户端可以使用以下代码来接受分块:
// javascriptcn.com 代码示例 var source = new EventSource('/events'); var buffer = ''; source.addEventListener('message', function(e) { buffer += e.data; while (/\n\n/.test(buffer)) { var chunk = buffer.substr(0, buffer.indexOf('\n\n')+2); buffer = buffer.substr(chunk.length); handle(chunk.replace(/(:?^\s*|\s*$)/g, '')); } }); function handle(chunk) { console.log(chunk); }
总结
本文介绍了 Server-Sent Events 技术,包括它的优点和常见问题及其解决方法,希望对大家在实际开发中有所帮助。SSE 提供了一种快速、实时、基于 HTTP 的单向通讯方案,适用于很多实时性要求高的前端应用场景。我们需要结合实际情况来选择技术方案,在使用 SSE 的同时也需要注意一些常见的问题,减少实际应用中的错误及故障。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6544e6037d4982a6ebeb2569