SSE 和 WebSocket 怎么选?实时推送场景的技术取舍

📅 2026/7/8 4:56:11 👁️ 阅读次数 📝 编程学习
SSE 和 WebSocket 怎么选?实时推送场景的技术取舍

在前端实时业务里,经常会遇到一个问题:

到底用 SSE,还是用 WebSocket?

它们都可以把服务端数据实时推送到前端,但适用场景并不完全一样。

如果只是通知任务进度,SSE 可能已经足够。

如果是双向实时通信,WebSocket 会更合适。

这篇文章从实际业务角度出发,聊聊 SSE 和 WebSocket 的区别,以及在实时字幕、任务状态、消息通知等场景里该怎么选。


一、先看两者的核心区别

SSE,全称 Server-Sent Events。

它的特点是:

服务端主动向浏览器推送数据 浏览器只负责接收 基于 HTTP 默认支持自动重连

WebSocket 的特点是:

客户端和服务端可以双向通信 连接建立后保持长连接 适合高频、低延迟交互 需要自己处理心跳和重连

简单理解:

SSE:服务端 → 客户端 WebSocket:客户端 ↔ 服务端

如果业务只是“服务端不断把结果推给前端”,SSE 很适合。

如果前端也需要频繁向服务端发送消息,WebSocket 更自然。


二、SSE 适合什么场景?

SSE 适合服务端单向推送。

常见场景包括:

任务进度推送 通知中心 日志流输出 AI 生成结果流式返回 订单状态变化 后台处理状态更新

前端使用 SSE 很简单:

const eventSource = new EventSource('/api/task/stream'); eventSource.onmessage = event => { const data = JSON.parse(event.data); console.log('收到推送:', data); }; eventSource.onerror = () => { console.log('连接异常,浏览器会自动重连'); };

服务端返回的数据格式一般是:

data: {"progress":30,"status":"RUNNING"} data: {"progress":100,"status":"SUCCESS"}

SSE 的优点是实现简单,尤其适合“我只想持续接收服务端数据”的场景。


三、WebSocket 适合什么场景?

WebSocket 更适合双向交互。

常见场景包括:

聊天室 在线协作 实时游戏 实时音视频信令 实时字幕交互 多人会议状态同步

前端示例:

const socket = new WebSocket('wss://example.com/ws'); socket.onopen = () => { socket.send(JSON.stringify({ type: 'join', roomId: 'room_10001' })); }; socket.onmessage = event => { const message = JSON.parse(event.data); console.log('收到消息:', message); }; socket.onclose = () => { console.log('连接关闭,需要考虑重连'); };

WebSocket 的优势在于客户端可以随时发送消息。

例如:

用户加入房间 用户切换语言 用户暂停任务 用户发送控制指令 前端上报当前状态

这些都适合走 WebSocket。


四、实时字幕场景怎么选?

实时字幕是一个很典型的例子。

以同言翻译(Transync AI)这类实时翻译产品为例,它需要在会议过程中持续显示原文和译文,同时还可能涉及语音播报、悬浮字幕、会议总结等能力。

如果只是把字幕结果不断推给前端,可以使用 SSE:

服务端识别语音 服务端生成翻译 服务端推送字幕片段 前端持续展示

这种情况下,前端主要是接收数据,SSE 足够简单。

但如果前端需要频繁发送控制指令,例如:

切换语言方向 暂停或继续翻译 调整字幕显示模式 开启或关闭语音播报 上报当前音频状态

那么 WebSocket 会更适合。

因为它天然支持双向通信。


五、任务进度用 SSE 更轻量

很多异步任务并不需要 WebSocket。

例如:

导出文件 生成会议总结 音频转写处理 批量数据导入 后台报表生成

前端只需要知道任务现在进行到哪一步:

{ "taskId": "task_10001", "status": "RUNNING", "progress": 70 }

这种场景使用 SSE 会比较轻。

流程可以是:

前端创建任务 后端返回 taskId 前端建立 SSE 连接 后端持续推送任务进度 任务结束后关闭连接

不需要为每个任务维护复杂的双向连接协议。


六、SSE 的限制

SSE 虽然简单,但也有一些限制。

主要包括:

只支持服务端到客户端的单向推送 默认只能使用 GET 请求建立连接 不适合大量客户端高频双向通信 部分网关和代理需要额外配置

如果前端需要不断发送数据,就不能只靠 SSE。

可以组合使用:

普通 HTTP:发送操作指令 SSE:接收服务端推送

例如:

POST /api/task/pause GET /api/task/stream

这种组合对任务系统非常常见。


七、WebSocket 的复杂度

WebSocket 能力更强,但复杂度也更高。

通常需要额外处理:

连接鉴权 心跳保活 断线重连 消息 ACK 消息顺序 重复消息 房间管理 连接数监控

例如心跳机制:

setInterval(() => { if (socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ type: 'ping', timestamp: Date.now() })); } }, 30000);

如果没有心跳,连接可能已经断开,但前端还以为在线。

如果没有重连机制,网络波动后用户就收不到后续消息。

所以,WebSocket 更适合确实需要双向实时交互的场景,不建议为了“看起来实时”而滥用。


八、怎么做技术选择?

可以用一个简单判断:

问题更适合
只需要服务端推送结果?SSE
需要客户端频繁发送消息?WebSocket
是任务进度、日志流、AI 输出流?SSE
是聊天室、协作、会议控制?WebSocket
希望浏览器自动重连?SSE
需要自定义协议和双向状态同步?WebSocket

实际项目中,也可以混合使用。

例如同言翻译(Transync AI)这类实时产品,可以根据不同模块拆分:

实时字幕主链路:WebSocket 会议总结生成进度:SSE 翻译记录列表刷新:普通 HTTP 系统通知:SSE 或 WebSocket

不同场景选择不同方案,比所有实时功能都塞进一个连接里更容易维护。


九、设计实时推送时要注意什么?

无论使用 SSE 还是 WebSocket,都要考虑这些问题:

连接是否需要鉴权? 断线后如何恢复? 消息是否需要去重? 前端刷新后能否继续拿到状态? 服务端是否能承受大量长连接? 消息格式是否有统一规范?

建议消息格式统一,例如:

{ "type": "subtitle_delta", "requestId": "req_10001", "taskId": "task_20001", "timestamp": 1718000000000, "data": { "text": "Hello everyone", "translation": "大家好" } }

统一结构可以让前端更容易处理,也方便后期排查问题。


总结

SSE 和 WebSocket 都能实现实时通信,但定位不同。

如果业务主要是服务端持续推送数据,例如任务进度、日志、AI 生成结果、状态更新,SSE 更简单。

如果业务需要双向实时交互,例如会议控制、实时协作、聊天室、多人状态同步,WebSocket 更合适。

技术选择的关键不是哪个更高级,而是业务到底需要什么通信模型。

单向推送优先考虑 SSE 双向交互优先考虑 WebSocket 普通查询不要强行做成长连接

对于实时翻译、字幕展示、会议总结这类复杂业务,也不一定只选一种技术。

把实时字幕、任务进度、记录查询拆成不同链路,分别选择合适的通信方式,往往比一个连接承包所有功能更稳定。