随着前端技术的不断更新,涌现出了越来越多的 Web 实时通信技术。其中,Server-Sent Events(简称 SSE)就是一种非常优秀的解决方案。SSE 基于传统的 HTTP 协议,能够实现服务器向客户端不间断地推送数据。但在实践中,却会遇到一个令人头疼的问题:客户端重连后,服务器可能向其发送已经接受过的消息。本文深入探讨这一问题,并提供解决方案。
原因分析
SSE 客户端与服务器之间的连接十分特殊。当客户端建立 SSE 连接时,服务器会向其发送一个指令,告诉客户端如何与服务器保持长连接。连接建立后,服务器会周期性地向客户端发送数据,直到连接中断。在连接中断后,客户端会向服务器再次请求建立连接,以保持实时通信。
但是,当客户端重连后,由于之前的连接已经关闭,服务器并不知道客户端是否已经接收到数据。因此,在比较简单的实现中,服务器会重新发送之前已经推送过的消息,导致客户端重复接收。这是一个非常严重的问题,会导致客户端数据存储异常、系统负载增加等问题。
解决方案
为了解决上述问题,我们需要在服务器端和客户端共同配合,实现数据的准确传输。具体实现过程如下:
服务器端
在服务器端,我们需要保留所有已经推送过的消息。当客户端请求建立连接时,需要向服务器发送一个最后一条已经接收到的消息的标识。服务器会根据这个标识,将之后推送的消息中未被客户端接收过的推送给客户端。这里需要我们自行实现推送的逻辑处理。示例代码如下:
// javascriptcn.com 代码示例 // 服务器端推送逻辑(node.js 环境) app.get('/event-stream', function(req, res) { res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); var lastEventId = req.headers['last-event-id'] || 0; var messages = getMessages(lastEventId); // 根据 lastEventId 获取未推送的消息 messages.forEach(function(message) { res.write('id: ' + message.id + '\n'); res.write('event: ' + message.name + '\n'); res.write('data: ' + message.data + '\n\n'); }); // 推送新消息 setInterval(function() { var message = getNextMessage(); res.write('id: ' + message.id + '\n'); res.write('event: ' + message.name + '\n'); res.write('data: ' + message.data + '\n\n'); }, 1000); });
客户端
在客户端,我们需要设置一个变量,存储最后一条已经接收到的消息的标识。这个变量可以在客户端本地存储中实现。当客户端重新连接服务器时,需要携带该标识,以便服务器可以向其推送正确的消息。同时,我们需要实现根据标识判断是否重复接收的逻辑。示例代码如下:
// javascriptcn.com 代码示例 // 客户端推送逻辑 var lastEventId = window.localStorage.getItem('lastEventId') || 0; var eventSource = new EventSource('/event-stream', {headers: {'Last-Event-ID': lastEventId}}); eventSource.addEventListener('myEvent', function(event) { if (event.lastEventId === lastEventId) { // 标识相同,说明已经接收过该事件 return; } // 处理事件逻辑 processEvent(event.data); // 更新最后一条已经接收到的消息的标识 lastEventId = event.lastEventId; window.localStorage.setItem('lastEventId', lastEventId); });
总结
通过上述方案,我们可以避免 SSE 客户端重连后多次接收同一个推送的问题。在实际应用中,我们还需要注意服务器性能、客户端存储容量等问题。本文提供的实现思路和示例代码仅作为参考,具体实现还需要考虑应用场景,结合业务逻辑进行优化。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65864e45d2f5e1655d0b29f2