Voocii博客
首页博客AI 热榜作品集读书友链工具关于

© 2026 Voocii. Built with Next.js & tRPC.

GitHubXEmailRSS


理解 SSE(Server-Sent Events):原理、流程与应用场景

技术rick-hayekrick-hayek2026年2月15日

什么是 SSE

SSE(Server-Sent Events)是 HTML5 标准的一部分,它允许服务器通过 HTTP 长连接主动向浏览器推送数据。与我们熟悉的"请求-响应"模式不同,SSE 建立的是一条服务器到客户端的单向数据流通道——客户端发起一次请求后,连接保持打开,服务器可以持续不断地向客户端"推送"消息,直到连接被关闭。

在 WebSocket 大行其道的今天,SSE 常常被忽视,但它其实是很多"服务器推送"场景下更简单、更轻量的选择。

动画演示

想对SSE有个快速的了解,可以 👉 点击此处在新页面中打开SSE演示动画

SSE 的工作原理

1. 基于 HTTP 的天然协议

SSE 的核心魅力在于它完全基于标准 HTTP 协议,不需要像 WebSocket 那样进行协议升级(Upgrade)握手。客户端只需要发起一个普通的 GET 请求,服务器返回一个特殊的 Content-Type,连接就会保持打开状态。

服务器需要设置的响应头:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

2. 数据格式

SSE 传输的数据遵循一套简单的文本协议,每条消息以 \n\n(空行)作为结束标志。核心字段包括:

data: 这是一条消息内容

data: 支持多行
data: 每行都以 data: 开头

event: userLogin
data: {"user": "Alice"}

id: 12345
data: 带编号的消息,用于断线重连时定位

retry: 3000
data: 设置重连间隔为3秒
  • data:实际传输的数据内容,可以是纯文本或 JSON 字符串
  • event:自定义事件类型,客户端可以监听特定类型的事件
  • id:消息的唯一标识,浏览器会记住最后收到的 id,断线重连时通过 Last-Event-ID 请求头告知服务器
  • retry:告诉浏览器断线后等待多久重连(毫秒)

3. 客户端实现

浏览器原生提供了 EventSource API,使用起来非常简单:

const eventSource = new EventSource('/api/stream');

eventSource.onmessage = (event) => {
  console.log('收到消息:', event.data);
};

eventSource.addEventListener('userLogin', (event) => {
  const data = JSON.parse(event.data);
  console.log('用户登录:', data.user);
});

eventSource.onerror = (err) => {
  console.error('连接出错:', err);
  // EventSource 会自动尝试重连,无需手动处理
};

EventSource 最贴心的一点是自动重连机制:一旦连接意外断开,浏览器会按照 retry 字段指定的时间自动重新发起连接,并携带 Last-Event-ID 请求头,让开发者可以在服务端实现"断点续传"式的消息补发。

4. 服务端实现(Node.js 示例)

app.get('/api/stream', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.flushHeaders();

  const timer = setInterval(() => {
    res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`);
  }, 1000);

  req.on('close', () => {
    clearInterval(timer);
    res.end();
  });
});

5. 完整流程图

客户端                              服务器
  |                                  |
  |---- GET /api/stream ------------>|
  |                                  |
  |<--- 200 OK ----------------------|
  |     Content-Type: text/event-stream
  |                                  |
  |<--- data: message 1 -------------|
  |<--- data: message 2 -------------|
  |<--- data: message 3 -------------|
  |          ...(连接保持打开)........|
  |                                  |
  |  (若连接断开,浏览器自动重连,      |
  |   并携带 Last-Event-ID)          |
  |---- GET /api/stream ------------>|
  |     Last-Event-ID: 12345         |
  |<--- data: message 4 -------------|

实际应用场景

SSE 特别适合"服务器单向、高频地向客户端推送更新"的场景:

  1. AI 对话流式输出:如 ChatGPT、Claude 等大模型应用中,文字逐字/逐词吐出的效果,正是通过 SSE 将模型生成的 token 流实时推送给前端

  2. 实时通知与提醒系统:如站内消息、系统公告、订单状态变更提醒

  3. 数据仪表盘 / 监控大屏:服务器指标、股票行情、体育赛事比分等需要持续刷新的只读数据展示

  4. 日志实时查看:CI/CD 流水线的构建日志、服务器运行日志的实时 tail

  5. 进度条与任务状态更新:文件上传处理进度、批量任务执行状态

  6. 社交媒体的实时动态流:如某用户的点赞数、评论数实时更新

优势分析

  • 实现简单:基于标准 HTTP,无需额外协议或复杂握手,浏览器原生 EventSource API 几行代码即可用
  • 自动重连:内置断线重连和消息 ID 追踪机制,开发者无需手写心跳与重连逻辑
  • 良好的基础设施兼容性:可以直接被现有的 HTTP 代理、负载均衡器、CDN、防火墙识别和处理,不像 WebSocket 需要专门的协议支持
  • 轻量:相比 WebSocket,不需要维护双向通道的复杂状态机,服务端实现和调试都更容易
  • 文本协议,调试友好:可以直接用浏览器开发者工具甚至 curl 查看数据流

劣势与不适用场景

  • 单向通信:SSE 只能服务器推送给客户端,客户端如果需要发数据回服务器,还是得依赖普通的 HTTP 请求。如果业务需要频繁的双向实时通信(如在线聊天、多人协作编辑、实时对战游戏),WebSocket 会是更合适的选择

  • 连接数限制:浏览器对同一域名下的 HTTP/1.1 并发连接数有限制(通常是 6 个),如果页面中同时存在多个 SSE 连接,很容易触及上限,导致其他请求被阻塞(HTTP/2 下这个问题会有所缓解)

  • 仅支持文本数据:SSE 只能传输 UTF-8 编码的文本,如果需要传输二进制数据(如音视频流),需要额外做 Base64 编码等处理,不如 WebSocket 原生支持二进制帧灵活

  • 不支持旧版 IE:虽然现代浏览器都已支持,但如果项目仍需兼容 IE11 等老旧浏览器,需要引入 polyfill

  • 某些反向代理/网关可能默认缓冲响应:如 Nginx 默认会对响应做缓冲,可能导致消息不能实时到达客户端,需要额外配置 proxy_buffering off 之类的选项

小结

SSE 是"轻量级服务器推送"场景下被低估的一个技术选项。如果你的业务只需要服务器向客户端单向、持续地推送数据——尤其是像 AI 流式生成这类场景——SSE 往往比 WebSocket 更简单、更省心、也更容易部署和调试。而一旦涉及到需要客户端也频繁向服务器发送数据的双向实时交互,WebSocket 仍然是更合适的选择。技术选型的关键,永远是先看清业务的真实通信模式,再决定用什么协议去实现它。

评论 (0)

暂无评论,快来抢沙发吧!

目录
  • 什么是 SSE
  • SSE 的工作原理
  • 实际应用场景
  • 优势分析
  • 劣势与不适用场景
  • 小结