服务端断开SSE连接时,前端需依赖服务端主动发送的eof类型消息(如data: {"type":"eof","reason":"maintenance"})来区分正常关闭与异常中断,而非仅靠onclose或onerror事件;收到eof后应立即调用close()并执行业务关闭逻辑,同时设标志位避免onclose中误判,自动重连须禁用以防止干扰。

服务端断开 SSE 连接时,前端无法自动区分是网络中断、服务端主动关闭,还是浏览器刷新/页面卸载,因此不能仅依赖 onerror 或 onclose 事件来判断“服务端已正常关闭”。关键在于服务端配合发送明确的终止信号,并前端主动识别。
服务端需发送明确的结束消息(而非直接断连)
SSE 协议本身没有“优雅关闭”指令,但可通过约定消息格式让前端感知服务端意图。推荐做法是:服务端在准备关闭前,先推送一条带特定 type 的消息,例如:
- data: {"type":"eof","reason":"maintenance"}
- 然后立即关闭连接(HTTP 响应体结束 + Connection: close)
这样前端收到 eof 消息后,可安全认为服务端已主动结束,而不是异常中断。避免只靠连接断开触发 onclose —— 它无法区分服务端正常结束和超时、代理切断等场景。
前端需监听 message 并识别 eof 类型
不要把逻辑全堆在 onclose 或 onerror 里。正确做法是:
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 在 onmessage 中解析 event.data,检查是否为 JSON 且 type === "eof"
- 如果是,调用 eventSource.close()(确保状态清理),并执行业务层面的“关闭完成”逻辑
- 同时设置标志位(如 isEofReceived = true),让 onclose 回调中跳过错误处理
示例片段:
es.addEventListener('message', e => {try {
const data = JSON.parse(e.data);
if (data.type === 'eof') {
es.close();
handleServerEnded(data.reason);
}
} catch { /* 忽略非 JSON 数据 */ }
});
onclose 和 onerror 的作用是兜底,不是主判断依据
这两个事件适用于真实异常场景:
- onclose:触发于连接被服务端关闭(无 eof 消息)、或浏览器自动重连失败后放弃时
- onerror:触发于网络失败、CORS 拒绝、响应非 200 等不可恢复错误
它们无法告诉你“服务端是否已处理完所有数据”。所以务必结合 eof 消息做主判断,onclose/onerror 只用于日志记录、降级提示或启动备用机制(如切换 WebSocket)。
注意重连行为干扰判断
默认情况下,EventSource 在连接断开后会自动重试(通常延迟几秒)。这会导致 onclose 后又触发 new connection → onopen,掩盖真实关闭意图。
- 若服务端明确发送 eof,应在收到后立即 es.close(),阻止自动重连
- 也可在首次连接时设置 es.readyState === 0(closed)后不再新建实例
- 避免在 onclose 里重新 new EventSource —— 除非你确认是临时故障且需要重连

















