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 本质上是:

  1. 先通过 HTTP 发起 Upgrade
  2. 服务端返回 101 Switching Protocols
  3. 后续切到 WebSocket 帧协议

从这一步开始,它就不再只是普通 HTTP 响应流了,而是一个真正的双向长连接通道。

这意味着什么

  • 客户端可以主动发消息给服务端
  • 服务端也可以主动发消息给客户端
  • 双方都可以持续发,不用每次重新建请求

所以它更适合:

  • IM
  • 房间广播
  • 实时协作
  • 双向控制
  • 实时游戏 / 信令

四、它们最核心的差别到底是什么

1. 通信方向

  • SSE:单向,服务端 -> 客户端
  • WebSocket:双向,客户端 <-> 服务端

2. 协议模型

  • SSE:还是 HTTP 体系里的流式响应
  • WebSocket:先 Upgrade,再切到独立帧协议

3. 使用心智

  • SSE:更像“服务端一直往外吐流”
  • WebSocket:更像“双方长期保持一个消息通道”

4. 复杂度

  • SSE:一般更简单
  • WebSocket:能力更强,但治理成本更高

5. 适合的数据形态

  • SSE:文本事件流特别合适
  • WebSocket:更适合复杂消息和双向事件

五、为什么 AI 场景经常优先用 SSE

因为很多 AI 场景,看起来像“实时交互”,其实数据流并不复杂。

典型链路往往是:

  1. 用户发起一次提问
  2. 服务端调用模型
  3. 模型持续吐 token
  4. 服务端边收到边往前端推
  5. 前端边接收边渲染

这条链路本质上仍然是:

客户端先发一个请求,服务端持续回一个流。

这正是 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。