SSE 推送中客户端手动关闭连接的解决方法
Server-Sent Events(SSE)是一种可靠的服务器向客户端实时推送数据的技术。但在实际开发中,我们常常会碰到客户端手动关闭 SSE 连接的情况,这时就需要一些解决方法。本文将介绍 SSE 推送中客户端手动关闭连接的解决方法,并提供相关示例代码。
一、SSE 推送简介
在介绍解决方法前,先简单介绍 SSE 推送。SSE 是浏览器 API 的一部分,它允许服务器通过单向连接向客户端传输消息。与 WebSocket 相比,SSE 不需要先建立连接,可以通过 HTTP 协议的一个 GET 请求来获取 SSE 流。SSE 总是使用同一个连接,直到连接断开或者超时。这使得 SSE 是一种非常适合实时应用程序的技术。
在服务器端,推送 SSE 消息只需要设置 HTTP Response Header 中的 Content-Type 为 text/event-stream,并在消息体中编写 SSE 格式的数据即可。以下是一段 Node.js 代码示例:
// javascriptcn.com 代码示例 res.writeHead(200, { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", "Connection": "keep-alive" }); // 模拟数据 const data = { time: new Date().toLocaleTimeString(), content: "Hello, SSE!" }; // 每 1 秒钟推送一次消息 setInterval(() => { res.write(`data: ${JSON.stringify(data)}\n\n`); }, 1000);
在客户端,使用 JavaScript 可以很方便地获取 SSE 流,并监听 onmessage
事件处理服务器推送的消息。以下是一个简单的示例:
const source = new EventSource('/sse'); source.onmessage = function(event) { console.log('Received message:', JSON.parse(event.data)); };
二、手动关闭 SSE 连接
在 SSE 推送中,一旦客户端关闭连接,服务器就不能向客户端发送任何消息,而断开连接的方式有多种,比如关闭标签页、点击浏览器中的“停止”按钮、刷新页面等。不过这些情况都无法通过程序控制,唯一可以由程序控制的就是调用 EventSource.close()
方法主动关闭连接。例如下面的代码片段:
const source = new EventSource('/sse'); // 5 秒后主动关闭连接 setTimeout(() => { source.close(); }, 5000);
服务器端代码并没有受到影响,依旧会按照设定的时间推送消息。但是客户端手动关闭连接后,所有推送的消息都会丢失。这时我们需要一些方法来解决这个问题。
三、解决方法
在 SSE 推送中,我们需要保证客户端和服务器之间的连接持久性。一旦连接断开,服务器应该尝试重新建立连接或者提示用户重新连接。为了实现这个目标,我们需要解决两个问题:
- 如何检测 SSE 连接是否已经断开?
- 如何在 SSE 连接断开后重新启动推送?
下面我们分别讨论这两个问题。
三、1、检测 SSE 连接是否已经断开
在 SSE 连接断开后,使用 EventSource.readyState
属性可以得到连接的状态。当连接断开时,readyState
的值会变成 EventSource.CLOSED
。以下是一个示例:
// javascriptcn.com 代码示例 const source = new EventSource('/sse'); source.onopen = function() { console.log('SSE connection is opened'); }; source.onclose = function() { console.log('SSE connection is closed'); }; setInterval(() => { if (source.readyState === EventSource.CLOSED) { console.log('SSE connection is broken, should reconnect'); // TODO: reconnect } }, 1000);
根据这个示例,我们可以通过检测 readyState
值的变化来得知连接是否断开。当 readyState
的值变成 EventSource.CLOSED
时,我们可以发起重连操作。
三、2、在 SSE 连接断开后重新启动推送
当 SSE 连接断开后,我们需要重新建立连接,并重新接收服务器推送的消息。为了实现这个目标,我们需要在客户端保存上一次 SSE 推送的 Last-Event-Id
数据、以及服务器最后推送消息的时间戳,以便重新建立连接后继续从上一次的位置推送消息。以下是一个示例:
// javascriptcn.com 代码示例 let lastEventId = ''; let lastTimeStamp = 0; const source = new EventSource('/sse'); source.onmessage = function(event) { // 获取服务器的时间戳 const timeStamp = new Date(event.timeStamp).getTime(); // 记录推送的数据以及时间戳和 lastEventId lastEventId = event.lastEventId; lastTimeStamp = timeStamp; console.log('Received message:', JSON.parse(event.data)); }; source.onclose = function() { console.log('SSE connection is closed, should reconnect'); // 重新建立连接时带上 lastEventId 和 timestamp source = new EventSource(`/sse?lastEventId=${lastEventId}&timeStamp=${lastTimeStamp}`); };
以上示例中,我们保存了上一次接收到的消息的 lastEventId
和时间戳 lastTimeStamp
。在服务器重新建立连接后,我们会带上这些参数来请求最新的 SSE 消息。这样,我们就保证了客户端在 SSE 连接断开后能够重新接收到服务器的消息。
四、总结
本文介绍了 SSE 推送中客户端手动关闭连接的解决方法,并提供了一些相关示例代码。在 SSE 推送中,我们需要确保连接的持久性,以便服务器可以向客户端持续推送消息。当连接中断时,我们还需要重新建立连接并继续接收消息。以上方法可以帮助开发者解决 SSE 推送中遇到的一些问题,并提高开发效率。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6534fd6d7d4982a6ebac7877