eventsource不是简单配url就能用,服务端必须严格返回200状态码、text/event-stream类型、keep-alive连接头,并持续write()输出符合data:/event:/id:格式且以\n\n结尾的消息;前端需用addeventlistener监听自定义事件,禁用res.end(),并处理跨域、超时与关闭。

EventSource 不是“配个 URL 就能收消息”的简单封装,它对服务端响应格式、HTTP 头、连接生命周期都有硬性要求;前端代码写得再标准,只要服务端漏掉 Content-Type: text/event-stream 或提前 res.end(),连接就会卡在 pending 或直接失败。
服务端响应头和流式输出必须严格达标
浏览器看到非 text/event-stream MIME 类型,比如 text/html 或 application/json,会直接拒绝解析,控制台报 EventSource's response has a MIME type ("text/html") that is not "text/event-stream"。这不是前端 bug,是服务端没按 SSE 协议说话。
- 必须返回状态码
200(302重定向、204无内容、304未修改都会导致连接失败) - 响应头至少包含:
Content-Type: text/event-stream、Cache-Control: no-cache, must-revalidate、Connection: keep-alive - Node.js/Express 中不能用
res.send()或res.json(),必须用res.write()持续输出,并且不调用res.end()直到客户端断开 - 每条消息结尾必须是双换行
\n\n,哪怕只发一个data:行,也得补上
前端监听自定义事件时容易漏掉 addEventListener
onmessage 只捕获没有 event: 前缀的消息;如果服务端发的是 event: user_update\ndata: {"id":123}\n\n,onmessage 完全收不到——这是最常被忽略的点,不是“没连上”,而是监听方式错了。
- 默认消息走
source.onmessage = handler - 自定义类型如
user_update、error,必须用source.addEventListener('user_update', handler) - 不要在
onerror里手动new EventSource()重连:浏览器自带重试逻辑,手动 new 会造成连接堆积,尤其在弱网下
跨域、本地开发与保活问题实际怎么处理
Chrome 完全不支持 file:// 协议下的 EventSource,本地双击 HTML 文件必失败;另外,Nginx 默认 60 秒超时、Safari 对缓存头更敏感、IE 全面不支持——这些不是边缘情况,而是上线前必须验证的真实约束。
- 跨域必须加
{ withCredentials: true },且服务端Access-Control-Allow-Origin不能设为*,得写具体域名 - 本地开发别双击 HTML,用
npx serve、python3 -m http.server或 VS Code Live Server 启 HTTP 服务 - 防代理/负载均衡断连:服务端每 30 秒左右发一次注释行,如
res.write(':keepalive\n\n'),浏览器忽略但能重置超时计时器 - 页面卸载前必须调用
source.close(),否则连接持续占用,可能触发浏览器同源并发连接上限(通常 6 个)
为什么一直 pending 却没报错?检查这三处
Network 面板里看到请求状态一直是 pending,说明连接已建但服务端没发出合法首条消息;此时控制台往往静默,根本不会触发 onerror,只能靠抓包或服务端日志定位。
- 看响应头有没有
Content-Type: text/event-stream—— 没有就停在这里改后端 - 看响应体第一行是不是以
data:、event:、id:或retry:开头 —— 普通 JSON 字符串如{"msg":"ok"}会被完全忽略 - 确认服务端没在第一次
write后就end了连接 —— Node.js 里常见错误是写了res.write(...); res.end();
真正难调试的从来不是前端那几行 new EventSource,而是服务端那几行响应头和 write 的时机与格式;一旦流格式出错,整个链路就静默失效,连错误提示都不给——这点比 WebSocket 还隐蔽。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











