eventsource需有效url且服务端返回text/event-stream;须同源或配置cors;禁用时间戳防缓存;统一用addeventlistener监听事件;retry由服务端控制;异常时需防抖检测readystate;必须显式close()防泄漏。

EventSource 构造函数必须传入有效 URL,且服务端要返回 text/event-stream
浏览器里 EventSource 不是万能的“长连接通用接口”,它只认 text/event-stream 响应头。如果后端返回 application/json 或没设 Content-Type,EventSource 会静默失败——既不触发 error,也不触发 message,控制台可能只有一条模糊的 “Failed to load resource”。
实操建议:
- 用
curl -H "Accept: text/event-stream" http://localhost:3000/events先手动验证响应头和数据格式 - URL 必须同源,或服务端明确设置
Access-Control-Allow-Origin: *(SSE 不支持带凭据的跨域) - 避免在 URL 后拼
?t=123类时间戳——部分代理或 CDN 会缓存,导致连接卡住
监听 message 和自定义事件要用 onmessage / addEventListener,不要 mix 用法
EventSource 的事件绑定有两种方式,但混用会导致监听丢失:
-
source.onmessage = handler是覆盖式赋值,第二次赋值会丢掉第一次 -
source.addEventListener('message', handler)是追加式,可多次调用 - 自定义事件(如
event: update)只能用addEventListener('update', ...),onmessage完全收不到
推荐统一用 addEventListener,示例:
const source = new EventSource('/api/notifications');
source.addEventListener('message', e => console.log('默认消息:', e.data));
source.addEventListener('user-login', e => console.log('登录事件:', JSON.parse(e.data)));
source.addEventListener('error', e => console.error('连接异常', e));
连接断开后自动重连有默认策略,但超时和重试间隔需后端配合
EventSource 默认会在连接关闭后 3 秒重试,这个间隔由服务端 retry: 字段控制(单位毫秒),不是前端可直接配置的。常见陷阱:
- 服务端没发
retry: 5000,浏览器就按默认 3 秒重连,可能压垮后端 - 服务端返回
retry: 0,浏览器会立即重连,容易触发高频请求 - 网络断开时,
error事件会连续触发,但readyState可能卡在0(CONNECTING)而非0→0→0循环,难以精准判断是否真断连
稳妥做法:在 error 回调里检查 source.readyState === 0,并加个防抖计数器,避免无限重试。
关闭连接必须显式调用 close(),否则可能泄漏连接
页面跳转、组件卸载时,如果不手动调用 source.close(),连接会持续存在,尤其在单页应用中容易积累多个闲置 EventSource 实例,占用服务器 SSE 连接数(Nginx 默认 limit 为 1024)。
- React 中在
useEffect清理函数里调用source.close() - Vue 中在
beforeUnmount钩子中关闭 - 注意:关闭后不可再调用
addEventListener,否则报错 “InvalidStateError: The object is in an invalid state.”
别依赖用户关标签页来释放连接——SSE 连接不会因为页面不可见而自动终止。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











