eventsource(sse)基于http长连接实现轻量级服务器推送,需服务端正确设置text/event-stream响应头、按规范格式发送data:/event:/id:消息并保持流不关闭,客户端用eventsource监听但仅支持get和url传参;复杂场景需fetch+readablestream手动解析;代理时应透传而非缓冲;须处理重连、心跳与连接生命周期。

EventSource(SSE)实现服务器数据推流,本质上是复用标准 HTTP 协议建立长连接,不需额外握手、不依赖新协议栈,因此天然比 WebSocket 更轻量。关键不在“能不能推”,而在“怎么让服务端持续吐出合规的流、客户端稳定接住”。下面从核心环节讲清实操要点。
服务端必须返回正确的响应头与数据格式
SSE 不是“随便写点东西发过去就行”。浏览器只认特定格式:
- 响应头 Content-Type 必须是 text/event-stream,且需在任何数据写出前设置(Node.js 中必须调用
res.writeHead(200, { 'Content-Type': 'text/event-stream', ... }),不能先res.write()再设头,否则报 ERR_INVALID_CHUNKED_ENCODING) - 每条消息以
data: xxx开头,结尾用两个换行符\n\n分隔;若需指定事件类型,加event: xxx行;若需携带 ID 用于断线续传,加id: 123 - 保持连接不关闭:服务端不能主动 end() 或 destroy() 响应流,而应持续 write(),或通过 setTimeout / setInterval / ReadableStream 等方式按需推送
客户端用 EventSource 监听,但要注意它只支持 GET 和无自定义 header
原生 new EventSource(url) 简单直接,但有硬限制:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 只能发 GET 请求,无法带 Authorization header、Bearer token 或请求体
- 所有认证参数只能拼在 URL 上(如
/api/sse?token=xxx),但 URL 长度受限(多数浏览器上限约 2000 字符),不适合复杂鉴权场景 - 跨域时需服务端明确返回
Access-Control-Allow-Origin,且不能设为*(若带 credentials)
若需 header 或 POST,就不能用原生 EventSource,得用 fetch + ReadableStream 手动解析 SSE 数据流——这虽稍复杂,但完全可控,也更贴近真实业务需求。
服务端代理场景:避免“收再转”,直接透传目标流
当你的后端只是中转 AI 推理等第三方 SSE 接口时,不必自己读取再重写响应。可直接做 HTTP 代理:
- 用 Node.js 的
http.request或fetch向目标地址发起流式请求 - 将目标响应的 headers(尤其是
Content-Type: text/event-stream)原样复制到客户端响应 - 用
pipe()或for await...of将目标响应体 chunk 直接写回客户端,零缓冲、低延迟 - 这样既省去 JSON 解析/序列化开销,又规避了服务端内存堆积风险
实际使用中要处理好连接生命周期
EventSource 自带重连机制,但默认行为未必符合业务预期:
- 断连后默认 3 秒重试,失败则指数退避(最多约 3 分钟)。可通过服务端返回
retry: 5000指令调整客户端重连间隔 - 客户端可用
eventSource.close()主动断开;服务端可通过关闭响应流触发客户端 onerror → onclose 流程 - 建议服务端加心跳(如每 15 秒发一条空 data 或注释
:keepalive),防止中间代理(如 Nginx、CDN)因超时主动断连 - 前端监听
onerror时不要盲目 close,先判断eventSource.readyState === 0(正在重连)还是=== 0 && eventSource.url === null(已彻底失败)










