什么是 SSE?
SSE(Server-Sent Events) 是一种在 Web 浏览器和服务器之间实现实时通信的技术,它允许服务端向客户端推送数据。
与传统的轮询不同,SSE 是基于 HTTP 长连接实现的,因此在服务器端有数据更新时,它可以主动向客户端推送数据,不需要客户端频繁地向服务器发起请求。
SSE 通常用于实现实时通知、实时聊天等应用场景。
心跳超时问题
由于 SSE 通常使用 HTTP 长连接,因此客户端需要不断向服务器发送心跳消息以保持连接,防止长连接被服务器断开。否则,长时间没有通信的连接可能被认为是死掉的连接,从而被服务器端断开。
SSE 规范中建议客户端每隔 3 秒发送一次心跳消息,同时建议服务器在长时间没有收到心跳消息时,应该主动向客户端发送一个特殊的消息以探测是否还存活。
然而,在一些网络较差或服务器压力较大的情况下,即使按照规范发送心跳消息,仍然有可能出现连接断开的情况,导致客户端无法接收到服务端推送的实时数据。
具体来说,就是客户端发送心跳请求,但服务端在一定时间内没有收到请求,就会认为这个连接已经断开了。
如何解决这个问题呢?
解决方法
一种可行的解决方法是在客户端和服务端分别设置超时时间,当一方没有及时响应时,另一方可以认为超时了,从而主动断开连接。
具体来说,客户端发送心跳请求时,可以设置一个超时时间,如果在该时间内没有收到服务端响应,就认为连接已经断开,并重新连接。服务端也可以设置一个类似的超时时间,当有客户端连接时,设置一个超时时间,在该时间内没有收到客户端的心跳请求,就主动断开该连接。这样可以避免死连接的情况出现。
以下是一份示例代码:
客户端
const eventSource = new EventSource('/sse'); let timeoutId; eventSource.addEventListener('open', e => { console.log('连接已打开'); resetTimeout(); }) eventSource.addEventListener('message', e => { console.log('收到数据:', e.data); resetTimeout(); }) eventSource.addEventListener('error', e => { console.log('连接出错:', e); resetTimeout(); }) function resetTimeout() { clearTimeout(timeoutId); timeoutId = setTimeout(() => { console.log('与服务器连接已超时,正在重连...'); eventSource.close(); connect(); }, 10000); } function connect() { eventSource.open(); }
服务端
const http = require('http'); const TIMEOUT = 20000; // 超时时间为 20s http.createServer((req, res) => { if (req.url === '/sse') { res.writeHead(200, { 'Content-Type': 'text/event-stream', // 设置超时时间 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*' }); // 初始化连接 res.write(':ok\n\n'); let timeoutId; req.on('close', () => { clearTimeout(timeoutId); }) req.socket.setTimeout(TIMEOUT); req.socket.on('timeout', () => { console.log('连接超时,断开连接'); req.socket.end(); }) timeoutId = setInterval(() => { console.log('发送心跳包'); res.write(':heartbeat\n\n'); }, 3000); } else { res.writeHead(404); res.end(); } }).listen(3000, () => { console.log('服务启动,监听 3000 端口'); })
总结
SSE 是一种实现实时通信的技术,但长时间没有通信的连接可能会被服务器端断开,导致客户端无法接收到实时数据。
为了避免这个问题,可以在客户端和服务端分别设置超时时间,当一方没有及时响应时,另一方可以认为超时了,从而主动断开连接。
以上是一份解决心跳超时问题的示例代码,可以参考使用。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b328e1add4f0e0ffc3a290