SSE与WebSocket选型指南:为什么Server-Sent Events又火了?

发布于

在后端架构领域近几年的演进中,有一个非常低调的变化:SSE(Server-Sent Events)正在悄然取代 WebSocket 的诸多应用场景。

有人可能会疑惑,SSE 作为 2006 年就存在的老技术,为何如今又焕发了生机?下面将结合实际项目经验,详细剖析这背后的原因。

## 架构选型的本质:切忌拿着锤子找钉子

开发实时通知系统时,很多人的第一反应是使用 WebSocket。但上线后往往会面临诸多运维噩梦:

👉 Nginx 反向代理需专门配置 WebSocket 超时和 Upgrade 头信息
👉 K8s Ingress 需修改 annotation,否则连接极易超时断开
👉 客户端断线重连逻辑繁杂,极易滋生 Bug
👉 企业级部署时,防火墙可能直接拦截 `ws://` 协议
👉 部分云厂商的 SLB 不支持长连接,被迫替换方案

折腾一圈后可能会发现,业务场景压根不需要双向通信,仅仅是客户端发起 HTTP 请求、服务端单向推送消息。用 WebSocket 无异于“高射炮打蚊子”。

架构选型最忌讳盲目套用熟悉的技术,必须先梳理清需求,再寻找合适的工具。

## 核心差异:两种底层通信模型

许多人习惯将 WebSocket 和 SSE 放在一起对比,实际上它们解决的是不同维度的通信需求。

**WebSocket = 全双工电话线 📞**
连接建立后,通信双方可随时互发消息。底层走独立的 `ws://` 协议,通过 HTTP 101 Upgrade 握手升级,随后脱离 HTTP 演变为全新的帧协议。

**SSE = 服务端广播电台 📻**
连接建立后,仅允许服务端向客户端单向推送数据。底层就是标准的 HTTP 长连接,只需将 Content-Type 设为 `text/event-stream`,服务端持续往 response body 写入数据即可。

## 核心参数对比

| 对比维度 | WebSocket | SSE |
| :--- | :--- | :--- |
| 通信方向 | 双向 ↕️ | 单向 ⬇️ |
| 底层协议 | `ws://`(独立协议) | HTTP(标准) |
| 断线重连 | 需自行实现 | 浏览器内置 ✅ |
| 代理/CDN/防火墙 | 易被拦截 | 天然兼容 ✅ |
| 运维复杂度 | 高 | 极低 ✅ |
| 数据格式 | 文本 + 二进制 | 仅文本(UTF-8) |

## 为什么近两年 SSE 突然爆发?

SSE 的复兴并非自身变强了,而是技术生态发生了剧变。

### 1. LLM 流式输出的完美契合
ChatGPT 的打字机效果(Streaming),是大模型边生成 token 边向客户端推送。在这个交互中,用户发请求用普通 HTTP POST,服务端单向流式推回结果,这正是 SSE 的教科书级场景。包括 OpenAI、Anthropic、智谱、通义、DeepSeek 等在内的主流大模型 API,均采用 SSE 进行流式输出。

### 2. 开发效率十倍差距
实现同一个“服务端推送”功能:

SSE 方案:
```javascript
// 前端:两行搞定
const source = new EventSource('/api/stream');
source.onmessage = (e) => console.log(e.data);

// 后端:设个 header 就行
res.setHeader('Content-Type', 'text/event-stream');
res.write(`data: ${JSON.stringify(msg)}\n\n`);
```

而 WebSocket 方案前后端加起来往往需要几百行代码,还需处理连接池、心跳、重连等各种边界情况。对于需快速验证的 AI 功能,SSE 是效率首选。

### 3. 基础设施兼容性完胜
`ws://` 协议在经过各类代理、网关和防火墙时,极易遭遇握手拦截、连接超时断开或 SSL 终端不透传等问题。例如金融机构的网关往往只放行标准 HTTPS 流量。
SSE 本质就是最标准的 HTTP,任何 CDN、网关看到的无非是一个普通的 HTTP 长连接,无需任何特殊配置。

### 4. 原生断线重连机制
在弱网环境下,WebSocket 断线需开发者自行实现指数退避重连和状态恢复。而 SSE 拥有浏览器原生的自动重连机制,并自带 `Last-Event-ID` 字段,服务端可据此继续推送后续数据。

### 5. 云原生架构的天然适配
现代的 Serverless、API Gateway、Service Mesh、K8s Ingress 组件对 HTTP 的支持是一等公民。SSE 走 HTTP 协议,Serverless 函数可直接返回 stream;而 WebSocket 需要维护有状态的持久连接,在 Pod 重调度或冷启动时极易丢失连接。

## WebSocket 不可替代的场景

尽管 SSE 优势明显,但在以下需要客户端频繁、低延迟主动发消息的场景中,依然是 WebSocket 的天下:

🎮 **多人实时游戏** — 玩家操作要双向实时同步,延迟要求 ms 级
💬 **IM 聊天** — 双方都要随时发消息,还要传图片、文件
📊 **协同编辑** — 多人同时改文档,OT/CRTP 算法需要双向实时
📈 **金融交易** — 行情推送 + 下单指令,双向都要求极低延迟
🏠 **IoT 设备控制** — 传感器上报 + 下发控制指令

## 架构选型决策树

总结实时系统的选型经验,可归纳为以下逻辑:

1. 业务需要客户端频繁主动发消息吗?是 ➡️ 用 WebSocket
2. 只需要服务端推送,且需传二进制数据?是 ➡️ 用 WebSocket
3. 只需要服务端推送文本 ➡️ 用 SSE

90% 的“实时推送”场景,SSE 都是更优解。好的架构师不是迷信新技术,而是在正确的场景选用最合适的工具。

评论(2)

其实在一些弱网环境或者对断线续传要求特别高的IM场景里,WebSocket依然需要深度定制。SSE虽然自带重连,但在某些复杂移动端场景下,原生重连机制的触发时机会有些玄学。

· 1 个赞

讲得很透彻!以前做简单消息推送总觉得必须上WebSocket,被Nginx和防火墙折磨得够呛,现在写AI流式接口直接用SSE确实清爽多了。

· 0 个赞