SSE 和 WebSocket 到底怎么选
这题在 AI 后端、实时系统、流式输出、Swoole、Go 服务面试里都特别容易被问。
很多人表面上会答:
- SSE 是单向
- WebSocket 是双向
这句话没错,但还不够。
真正更好的回答,应该讲清楚:
- 它们各自的运行方式
- 为什么 AI 场景经常优先用 SSE
- 为什么不是所有“实时”都该上 WebSocket
- 两者在工程治理上的真实成本
一、先给结论
如果只需要:
- 服务端持续把 token、日志、进度、状态流式推给前端
优先考虑 SSE。
如果需要:
- 客户端和服务端都频繁主动发消息
- 任务控制、多人协作、房间消息、双向实时交互
更适合 WebSocket。
一句话版就是:
单向流式推送优先 SSE,双向实时交互优先 WebSocket。
二、SSE 到底是什么
SSE,Server-Sent Events,本质不是一个全新的独立协议栈,而是:
- 基于 HTTP 的流式响应
- 服务端不立刻结束响应
- 而是持续往响应流里写事件
- 客户端持续读取这些事件
所以它的通信方向天然就是:
服务端 -> 客户端
这意味着什么
它更像:
- 客户端先发起一次请求
- 服务端不断往回写内容
而不是:
- 双方各自随时发消息
它常见长什么样
服务端一般会返回:
Content-Type: text/event-stream
数据里常见字段有:
data:event:id:retry:
浏览器端常用的是:
EventSource
三、WebSocket 到底是什么
WebSocket 本质上是:
- 先通过 HTTP 发起 Upgrade
- 服务端返回
101 Switching Protocols - 后续切到 WebSocket 帧协议
从这一步开始,它就不再只是普通 HTTP 响应流了,而是一个真正的双向长连接通道。
这意味着什么
- 客户端可以主动发消息给服务端
- 服务端也可以主动发消息给客户端
- 双方都可以持续发,不用每次重新建请求
所以它更适合:
- IM
- 房间广播
- 实时协作
- 双向控制
- 实时游戏 / 信令
四、它们最核心的差别到底是什么
1. 通信方向
- SSE:单向,服务端 -> 客户端
- WebSocket:双向,客户端 <-> 服务端
2. 协议模型
- SSE:还是 HTTP 体系里的流式响应
- WebSocket:先 Upgrade,再切到独立帧协议
3. 使用心智
- SSE:更像“服务端一直往外吐流”
- WebSocket:更像“双方长期保持一个消息通道”
4. 复杂度
- SSE:一般更简单
- WebSocket:能力更强,但治理成本更高
5. 适合的数据形态
- SSE:文本事件流特别合适
- WebSocket:更适合复杂消息和双向事件
五、为什么 AI 场景经常优先用 SSE
因为很多 AI 场景,看起来像“实时交互”,其实数据流并不复杂。
典型链路往往是:
- 用户发起一次提问
- 服务端调用模型
- 模型持续吐 token
- 服务端边收到边往前端推
- 前端边接收边渲染
这条链路本质上仍然是:
客户端先发一个请求,服务端持续回一个流。
这正是 SSE 最舒服的使用方式。
所以 SSE 特别适合
- token streaming
- 实时进度
- 分段文本结果
- 日志输出
- 简单通知流
这里有一个很重要的认知
很多人会把“AI 实时输出”自动等价成“必须 WebSocket”。
其实不是。
很多 AI 输出只是:
- 单向文本流
那 SSE 往往就够了,而且更简单。
六、什么时候虽然是 AI 场景,但更适合 WebSocket
如果你的 AI 系统已经不只是“单向吐 token”,而是变成下面这些模式,WebSocket 会更合适:
- 前端要频繁发控制指令
- 用户要实时取消、暂停、继续、插队
- 有多个消息类型同时存在
- 同一个会话里既有文本流,又有状态事件、工具事件、协作事件
- 多人共同看一个会话或共同编辑
- 做双向语音、实时音频流
这时候系统更像“实时消息系统”,而不只是“HTTP 输出流”。
七、一个面试里很加分的细节点
很多人会说:
- “只要需要取消生成,就必须 WebSocket”
其实这句话并不严谨。
因为很多系统完全可以这样做:
- 输出结果用 SSE
- 取消任务走单独的 HTTP 接口
也就是说:
- 流式输出和控制接口
- 不一定非要绑在同一条连接上
这点如果你能讲出来,说明你不是在机械背答案,而是在按系统边界做判断。
八、SSE 的工程成本到底在哪
别只说“简单”,简单不等于没坑。
真正要注意的是:
1. 代理缓冲
如果 Nginx、网关、CDN、反向代理把响应缓冲住了,前端可能就收不到实时流。
所以要特别关注:
- 是否关闭了流式响应缓冲
- 是否允许长时间不结束的响应
2. 空闲超时
中间层可能会因为长时间没有数据就断开连接。
所以很多 SSE 实现会定期发:
- 注释行
- keepalive
- 心跳事件
3. 自动重连
SSE 在浏览器侧通常会自动重连,这既是优点,也是要治理的点。
因为你还要考虑:
- 重连后从哪里继续
- 会不会重复消费事件
- 事件是否需要带
id
4. 事件续传
如果你希望断开后继续接着上次的位置恢复,就要考虑:
- 事件 ID
- 最近事件缓存
- 是否支持按
Last-Event-ID补发
九、WebSocket 的工程成本到底在哪
WebSocket 的问题从来不只是“把连接建起来”。
真正难的是:
1. 心跳
要知道连接是不是还活着。
2. 断线重连
要知道:
- 什么时候重连
- 如何退避
- 重连后如何恢复上下文
3. 鉴权
要考虑:
- 握手阶段怎么带 token
- token 过期怎么办
- 重连后怎么重新认证
4. 多实例路由
如果你的服务有多个实例,就不能假设:
- 用户永远连在当前机器上
所以要有:
- Redis Pub/Sub
- Kafka
- 连接网关
- 用户与连接的映射关系
5. 广播与热点
如果很多人都在同一个房间、频道、会话里,广播成本和热点连接都可能很高。
十、怎么真正做选型
你可以按下面这条线来判断:
优先选 SSE
如果满足大部分条件:
- 主要是服务端单向推送
- 主要传文本或事件流
- 主要是 AI token streaming / 进度 / 日志
- 希望实现简单一点
- 不想过早引入长连接治理复杂度
优先选 WebSocket
如果满足大部分条件:
- 客户端也要实时主动发消息
- 双向交互非常频繁
- 有多人房间、协同、状态同步
- 有复杂消息类型
- 有双向控制、低延迟要求
十一、项目里怎么讲会更像做过的人
你可以这样说:
我会先看数据流是不是天然单向。如果只是模型结果流式返回给前端,我一般优先用 SSE,因为它更贴近 HTTP 流式响应,接入简单,成本更低。如果系统进一步需要任务控制、多人协作、状态同步或者客户端频繁主动发消息,我才会上 WebSocket,因为它本质上是在维护一个双向消息通道,能力更强,但连接治理、鉴权、心跳和多实例路由也会更复杂。
这段会比只说“一个单向,一个双向”强很多。
十二、30 秒版怎么答
SSE 和 WebSocket 的核心区别在于通信方向和治理成本。SSE 是基于 HTTP 的单向流式推送,特别适合 AI token streaming、进度流和日志流;WebSocket 是升级后的双向长连接,更适合实时交互、任务控制、多人协作这类场景。我的判断原则是:单向流式优先 SSE,双向实时交互优先 WebSocket。
十三、1 分钟版怎么答
我不会只背“一个单向一个双向”,而是看场景的数据流。如果前端只是接收模型 token、任务进度、日志这些服务端持续输出的数据,SSE 往往就够了,因为它还是 HTTP 流式响应,接入简单,前端也好处理。WebSocket 更像一个真正的双向消息通道,适合客户端和服务端都要频繁发消息的场景,比如实时任务控制、房间广播、多人协作、双向音频流。它能力更强,但也会带来心跳、重连、鉴权、多实例路由这些治理成本。
十四、3 分钟版怎么答
我理解 SSE 和 WebSocket 的关键,不是只背协议名,而是看系统到底需要什么通信模型。SSE 本质上是 HTTP 上的流式响应,服务端持续往一个响应里写事件,客户端持续接收,所以特别适合单向流式输出,比如 AI token streaming、任务进度、日志流。它的优势是接入简单,比较贴近 HTTP 心智,但也要注意代理缓冲、空闲超时、自动重连和事件续传。
WebSocket 则是先通过 HTTP Upgrade 建链,后续走独立帧协议,形成真正的双向长连接通道。它适合的是实时消息、任务控制、多人协作、房间广播、双向语音这些场景。它的优势是交互能力强,但代价是长连接治理复杂度明显更高,比如心跳、断线重连、token 续期、多实例消息路由、连接清理和广播成本。
所以我的选型原则通常是:如果只是服务端单向把结果持续推给前端,我优先用 SSE;如果客户端也要高频主动发消息,或者系统已经变成一个真正的实时消息系统,我才会上 WebSocket。甚至有些 AI 系统可以把两者拆开,用 SSE 做输出流,用普通 HTTP 做取消控制,不一定非要把所有实时动作都塞进 WebSocket。