SSE (Server Send Events) 是基于HTTP的,服务端可以主动推送消息到客户端。是单向的。
应用场景:AI聊天流式响应、MCP的SSE通信
由于SSE是长连接的,那么如果发生断连了怎么办。
SSE是应用层协议,而断连通常是TCP连接断开。针对TCP连接,如果断开,那么连接状态不会被保留。并且TCP通常是操作系统维护,应用程序通常无法修改。所以要实现SSE重连,需要在应用层代码中进行状态维护,比如保存消息idx,同时给客户端推送每条消息时携带idx。这样即使断连,客户端也可以通过重新连接,并且在请求头携带这个idx,这样服务端就知道应该从哪个idx开始继续推送。
浏览器的SSE重连。
服务端:
const http = require('http');
const fs = require('fs');
// 存储客户端连接(用于模拟主动断连)
let clientResponses = [];
const server = http.createServer((req, res) => {
if (req.url === '/') {
// 提供前端页面
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(fs.readFileSync('index.html'));
} else if (req.url === '/stream') {
// SSE 流处理
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// 记录客户端连接,用于后续主动断连
clientResponses.push(res);
req.on('close', () => {
clientResponses = clientResponses.filter(r => r !== res);
console.log('客户端连接关闭');
});
// 发送初始事件
let eventId = 1;
const interval = setInterval(() => {
// 推送带 ID 的事件
res.write(`id: ${eventId}\n`);
res.write(`data: 这是第 ${eventId} 条消息\n\n`);
console.log(`已推送事件 ID: ${eventId}`);
eventId++;
}, 2000);
// 10秒后主动关闭连接(模拟服务器断连)
setTimeout(() => {
clearInterval(interval);
res.end(); // 关闭当前连接
console.log('服务器主动断开连接(模拟断连)');
}, 10000);
} else if (req.url === '/close-all') {
// 手动触发所有连接关闭(可选,用于测试)
clientResponses.forEach(res => res.end());
clientResponses = [];
res.end('已关闭所有连接');
}
});
server.listen(3000, () => {
console.log('SSE 服务器运行在 http://localhost:3000');
});
客户端:
<!DOCTYPE html>
<html>
<body>
<h1>SSE 自动重连测试</h1>
<div id="messages"></div>
<script>
// 连接 SSE 服务
const source = new EventSource('/stream');
const messagesDiv = document.getElementById('messages');
// 接收事件时的处理
source.onmessage = (event) => {
console.log(event)
const message = document.createElement('div');
message.textContent = `收到消息(ID: ${event.lastEventId}): ${event.data}`;
messagesDiv.appendChild(message);
console.log('收到消息:', event.data, '事件ID:', event.lastEventId);
};
// 连接打开时
source.onopen = () => {
console.log('SSE 连接已打开');
};
// 连接错误时(包括断连)
source.onerror = (error) => {
console.error('SSE 连接错误:', error);
if (source.readyState === EventSource.CLOSED) {
console.log('连接已关闭,等待浏览器自动重连...');
} else if (source.readyState === EventSource.CONNECTING) {
console.log('正在尝试重连...');
}
};
</script>
</body>
</html>
浏览器作为应用层实现了SSE重连,可以通过lastEventId这个字段来标识消息顺序。
4万+

被折叠的 条评论
为什么被折叠?



