← [ BACK_TO_NOTES ]

SSE

一种基于 HTTP 的服务器向客户端单向推送数据的技术(EventSource / text/event-stream)。

#concept #growing #network #browser #http #javascript

[!info] related notes

SSE

一种基于 HTTP 协议的服务器向客户端单向推送数据的技术。

如果说 WebSocket 是一条“双向高速公路”,那么 SSE 就是一个“单向广播电台”。客户端打开收音机(建立连接)调到特定频道后,就只能被动接收电台(服务器)源源不断发送过来的节目内容,而不能用收音机向电台喊话。

随着 ChatGPT 等 AI 大模型的爆火,你看到的那些 AI 回复时“打字机式”逐字弹出的效果,绝大多数就是基于 SSE 技术实现的。

下面我们来详细拆解 SSE 的工作原理、特点以及它与 WebSocket 的区别。


一、 SSE 是如何工作的?

与 WebSocket 需要一套独立的复杂握手和帧结构不同,SSE 完全基于标准的 HTTP 协议,极其轻量和简单。

1. 建立连接

  • 客户端向服务器发送一个普通的 HTTP GET 请求。

  • 服务器接收到请求后,返回一个特定的 HTTP 响应头,告诉客户端:“我要开始流式传输数据了,请保持连接不要断开。”

    其中最关键的响应头是:

    Content-Type: text/event-stream (声明内容类型为事件流) Cache-Control: no-cache (禁止缓存) Connection: keep-alive (保持连接不断开)

2. 数据传输

连接建立后,服务器就可以随时向客户端发送文本数据了。SSE 的数据格式非常简单,纯文本,按行分割。每条消息由一个或多个字段组成,以两个换行符 \n\n 结束。

一个标准的数据块长这样:

id: 101
event: message
data: Hello, World!
  • data: 核心字段,包含实际传输的数据。如果数据有多行,可以写多个 data:。
  • id: 事件的唯一标识符。如果连接断开,浏览器会自动重连,并带上最后一次接收到的 ID(通过 Last-Event-ID 请求头),方便服务器接着推送未完成的数据。
  • event: 自定义事件类型。前端可以监听不同的事件名(默认是 message)。

3. 自动重连(SSE 的超强天赋)

这是 SSE 相比 WebSocket 的一大杀手锏:浏览器原生支持断线重连。如果网络突然波动导致连接断开,浏览器底层的 EventSource API 会自动尝试重新连接服务器,不需要开发者手动写复杂的重连逻辑。


与其他实时通信方式的关系

SSE 本页只维护协议本体。SSE、WebSocket 与 Polling 在通信方向、基础设施、断线恢复和应用场景上的系统对比统一维护在 实时通信:SSE vs WebSocket vs Polling。

三、 典型应用场景

总的来说,只要你的业务需求是“服务器单向高频向客户端发消息,而客户端很少向服务器发消息”,首选 SSE。

  • AI 大模型对话流(LLM Streaming): ChatGPT、Gemini 的逐字输出效果,这是目前 SSE 最火的应用场景。客户端只需发送一次 Prompt,服务器随后将生成的 Token 持续不断地用 SSE 推送回来。
  • 实时通知/消息接收: 比如社交网站的系统通知、邮件到达提醒。
  • 金融/股票实时行情: 前端只需要看最新的价格走势,不需要向服务器发送大量数据。
  • 日志监控平台: 实时在网页端查看服务器滚动的系统日志。
  • 赛事比分直播: 实时更新体育比赛的比分和文字直播。

四、AI 对话中的暂停与中断

在 AI 流式对话场景中,用户可能需要中途停止生成。这涉及前后端的状态同步问题:

  • 前端用 AbortController 取消 fetch 请求,触发后端 req.on('close')
  • 后端感知连接关闭后停止模型流,避免 token 浪费
  • 消息状态需要设计状态机(idle / streaming / cancelling / cancelled / done / error)
  • 流式回调中每次 append chunk 前检查消息状态,防止旧 chunk 继续写入

详见 SSE 流式输出的暂停与中断。

学习检查

不看正文回答:

  1. SSE 为什么仍然是 HTTP 响应,而不是另一套独立双向协议?
  2. text/event-stream 中 event、data、id、retry 分别表达什么?
  3. 为什么 SSE 事件必须按协议边界解析,而不能把任意网络 chunk 直接 JSON.parse?
  4. EventSource 原生重连与“业务事件不重复/不丢失”为什么不是同一件事?
  5. 前端 Abort 连接后,为什么不能自动推导服务端业务任务已经停止?
  6. 代理缓冲或压缩为什么可能制造“假流式”?
  7. 什么时候应该去 SSE vs WebSocket vs Polling 做方案选择,而不是继续在 SSE 本体里找答案?
创建于 2026/3/13 更新于 2026/10/16
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本