在前端实时业务里,经常会遇到一个问题:
到底用 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 普通查询不要强行做成长连接对于实时翻译、字幕展示、会议总结这类复杂业务,也不一定只选一种技术。
把实时字幕、任务进度、记录查询拆成不同链路,分别选择合适的通信方式,往往比一个连接承包所有功能更稳定。