← 返回题目列表

SSE(Server-Sent Events)是什么?和 WebSocket 怎么选?

高频 中等 第 13 / 27 题 更新于 2026/07/31
SSE服务器推送EventStreamWebSocket

简化版

SSE(Server-Sent Events,服务器发送事件)是一种基于普通 HTTP 的服务器单向推送技术:客户端发一个普通 HTTP 请求,服务器不关闭连接,而是持续用 text/event-stream 格式一条条往下推数据。它只能服务器→客户端单向,胜在简单——就是一个长时间不结束的 HTTP 响应,天然走 HTTP/HTTPS、自动重连、带事件 id。要双向就用 WebSocket,只要服务器单向推(如 AI 流式输出、消息通知、进度条)SSE 更轻量。ChatGPT 那种「文字一个个蹦出来」用的就是 SSE。

详细版

SSE 的本质:一次「永不结束的 HTTP 响应」。

客户端:
  GET /events HTTP/1.1
  Accept: text/event-stream

服务器:
  HTTP/1.1 200 OK
  Content-Type: text/event-stream
  Cache-Control: no-cache
  Connection: keep-alive

  data: 第一条消息\n\n
  data: 第二条消息\n\n
  ...(连接一直开着,有数据就继续写)

数据格式是纯文本,每条以字段行组成、\n\n 分隔:

  • data: 消息内容(可多行)。
  • event: 自定义事件名(前端用 addEventListener('事件名') 监听)。
  • id: 事件 id,浏览器会记住,断线重连时通过 Last-Event-ID 头带回,实现断点续传
  • retry: 告诉浏览器重连间隔(毫秒)。

浏览器端用内置 EventSource 接收,且自动重连

const es = new EventSource('/events');
es.onmessage = (e) => console.log(e.data);
es.addEventListener('progress', (e) => { /* 自定义事件 */ });

SSE vs WebSocket 速览:

维度SSEWebSocket
方向服务器→客户端单向双向全双工
底层普通 HTTP(长响应)借 HTTP 握手后独立帧协议
数据只能文本(UTF-8)文本 + 二进制
自动重连内置(浏览器自动)要自己实现
断点续传内置(Last-Event-ID)要自己实现
复杂度低,就是个 HTTP 接口较高
代理/防火墙友好好(就是 HTTP)好(借 HTTP 握手)

完整版教学

一、SSE 解决的问题:只要「服务器单向推」

先厘清需求光谱。「实时」有两种:

  • 双向实时:聊天、协作、在线游戏——客户端和服务器都要随时主动发。这类只能上 WebSocket
  • 单向推送:服务器有新数据就通知客户端,客户端基本不需要频繁回话——股票行情、系统通知、任务进度、日志滚动、AI 流式回答。这类用 WebSocket 属于「杀鸡用牛刀」,SSE 刚好合适。

SSE 就是为第二类而生:它不追求双向,专注把「服务器持续推」这件事做得极简

二、SSE 为什么这么简单——它就是个 HTTP 响应

WebSocket 要专门的握手、帧协议、掩码、心跳,而 SSE 什么新协议都没发明

  • 客户端发一个普通 GET 请求。
  • 服务器返回 Content-Type: text/event-stream,然后不结束响应,保持连接打开,有数据就往响应流里写一段 data: xxx\n\n
  • 浏览器的 EventSource 边收边解析,每收到一个完整事件就触发回调。

因为它从头到尾都是 HTTP,所以:能直接走 HTTPS、天然穿过绝大多数代理和防火墙、能复用 HTTP 的认证/Cookie/压缩、服务端实现只要「持有一个 response 对象不断 write」即可。后端框架里往往几行代码就能搞定。

三、内置能力:自动重连 + 断点续传

SSE 有两个 WebSocket 需要自己造轮子、而它协议内置的杀手锏:

① 自动重连——连接断了,浏览器的 EventSource自动重新发起请求,默认间隔约 3 秒,服务器还能用 retry: 字段自定义间隔。开发者什么都不用写

② 断点续传(Last-Event-ID)——服务器给每条消息带 id:,浏览器会记住最后收到的 id;断线重连时,浏览器自动在请求头带上 Last-Event-ID,服务器据此从断点之后继续推,不丢消息、不重复。

服务器推:  id: 1001\n data: 消息A\n\n
(断线)
浏览器重连:GET /events   Last-Event-ID: 1001
服务器:    从 1001 之后继续推 → id: 1002 ...

这套「自动重连 + 续传」对做可靠消息推送非常省心,是 SSE 相对 WebSocket 的一大优势。

四、SSE 的三个硬限制

选型时必须知道 SSE 的短板:

  1. 只能单向:客户端要发数据,得另开一个普通 HTTP 请求。真正频繁双向交互就别硬用 SSE。
  2. 只能传文本(UTF-8):要传二进制得先 base64 编码(会膨胀约 33%)。传大量二进制选 WebSocket。
  3. HTTP/1.1 下的连接数限制:浏览器对同一域名的并发连接有上限(约 6 个),每个 SSE 都占一条长连接,多开几个页面/标签就可能耗尽。HTTP/2 下靠多路复用,这个问题基本消失(多个 SSE 复用一条连接),所以 SSE + HTTP/2 是推荐组合。

五、经典场景:为什么 AI 流式输出用 SSE

大模型「打字机效果」(文字一个个往外蹦)几乎清一色用 SSE,因为它完美契合:

  • 交互是天然单向的——用户发一次问题(普通 POST),然后服务器持续把生成的 token 一段段推回来,客户端只管接收显示。
  • 用 SSE 服务端实现极简:模型每生成一点就 write 一段 data:,前端 EventSource 边收边渲染。
  • 不需要 WebSocket 的双向和二进制能力,SSE 更轻、更好接入现有 HTTP 基础设施(网关、鉴权、限流全复用)。

(注:OpenAI 等 API 用的是 POST + SSE 流式响应,浏览器原生 EventSource 只支持 GET,所以前端常用 fetch 手动读取流来兼容 POST,但底层数据格式仍是 SSE 的 text/event-stream。)

六、到底怎么选:按场景决策

  • 要双向、要传二进制、高频互发(聊天、协作、游戏)→ WebSocket
  • 只要服务器单向推、想省事、要自动重连/续传(通知、行情、进度、日志、AI 流式)→ SSE
  • 偶尔查一下有没有新数据、实时性要求不高 → 普通轮询也够,别过度设计。

七、常见误区与追问

考点正确口径
SSE服务端通过 HTTP 长连接单向推送文本事件
WebSocket全双工双向通信
适用通知、日志、进度、行情等服务端到客户端推送
HTTP/1.1 200 OK
Content-Type: text/event-stream

event: message
data: hello

data: next update

SSE 是“服务端持续说”,WebSocket 是“双方都能随时说”;别把单向推送复杂化。

  • 误区:SSE 和 WebSocket 完全一样。 SSE 基于 HTTP 单向推送文本,WebSocket 是全双工帧协议。
  • 误区:SSE 只能发送一次消息。 SSE 连接保持打开,服务端可持续发送多个事件。
  • 误区:SSE 适合大量客户端上行消息。 客户端频繁发送消息仍要走普通 HTTP 请求或改用 WebSocket。
  • 追问:SSE 如何断线重连? 浏览器 EventSource 内置重连,并可用 Last-Event-ID 续接。
  • 追问:SSE 的 Content-Type 是什么? 使用 text/event-stream,事件按文本格式分行发送。
  • 追问:SSE 的限制是什么? 只支持服务端到客户端单向推送,二进制和复杂双向交互不如 WebSocket。

八、加强记忆

SSE 是基于普通 HTTP 的服务器单向推送:一次「不结束的 HTTP 响应」,用 text/event-stream 一条条推 data:。优点是简单(就是 HTTP 接口)、浏览器 EventSource 自带自动重连 + Last-Event-ID 断点续传。限制:单向、只传文本、HTTP/1.1 有并发连接数上限(HTTP/2 解决)。要双向/二进制/高频互发用 WebSocket;只要服务器单向推(通知、行情、进度、AI 流式输出)用 SSE 更轻。