本文对比了 WebSocket 与 Server-Sent Events(SSE),给出选择建议并附带实现注意事项与示例代码片段,帮助在实时功能设计上做出权衡。
概述
WebSocket 是双向(full-duplex)的实时通信协议,适用于需要客户端与服务器互相推送数据的场景。SSE(通过浏览器的 EventSource)是单向(server->client)的实时推送方案,基于标准 HTTP,适合服务器向客户端持续推送事件流。
核心区别
- 双向 vs 单向:WebSocket 支持双向通信;SSE 仅支持服务器到客户端的单向事件流。
- 连接模型:WebSocket 通过升级 HTTP 到 ws:// 或 wss:// 建立长连接;SSE 使用普通 HTTP 长轮询/持久连接(text/event-stream)。
- 浏览器支持与复杂度:主流浏览器均支持 SSE 与 WebSocket,但 WebSocket 更通用于复杂交互场景;SSE 实现简单,自动重连和事件ID支持。
优缺点对比(简表)
- WebSocket:低延迟、双向、效率高,但需要处理协议帧、心跳、负载均衡粘性等。
- SSE:实现简单、基于 HTTP、自动重连、文本事件友好,但不支持二进制帧,单连接对大规模客户端数有影响(需要连接数规模评估)。
何时选 SSE
- 主要场景是服务器向客户端推送实时更新(通知、实时日志、状态订阅、监控面板)且无需客户端频繁发送消息。
- 希望利用 HTTP/2 或现有 HTTP 基础设施简化部署。
何时选 WebSocket
- 需要双向低延迟通信(协作编辑、多人实时互动、游戏、实时协商)。
- 需要传输二进制数据或自定义消息协议时。
实践建议与注意事项
- 负载与伸缩:长连接会占用服务器文件描述符,需配合 proxy(如 Nginx/TCP 代理)或使用专门的连接层(如 socket server、消息队列)。WebSocket 常需要 sticky session 或使用共享会话层(Redis、消息总线)。
- 心跳/保活:两者都需要心跳/重连策略以检测死连接;SSE 有浏览器自动重连,仍建议服务器端发送心跳注入。示例心跳:发送
: keep-alive\n\n或空事件。 - 安全性:使用 TLS(wss:// / https)保护数据,校验来源与认证(JWT、Cookie、签名)。
- 退化策略:在受限环境下(代理或防火墙限制 WebSocket),考虑降级为 SSE 或轮询。
简单示例(SSE 服务端 Node.js)
// express 示例
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.write('retry: 3000\n\n');
const id = setInterval(() => {
res.write(`data: ${JSON.stringify({ t: Date.now() })}\n\n`);
}, 2000);
req.on('close', () => clearInterval(id));
});
简单示例(WebSocket 服务端 Node.js + ws)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (msg) => console.log('recv', msg));
ws.send(JSON.stringify({ hello: 'world' }));
});
结论与建议
对于以服务器推送为主的功能(如实时通知、日志、仪表盘),优先考虑 SSE:实现简单、与 HTTP 友好、可在浏览器端自动重连。对于需要双向通信或二进制传输的复杂实时交互场景,选择 WebSocket。无论选择哪种方案,都应评估连接数、心跳策略、负载均衡和安全策略。
- 参考:WebSocket RFC、MDN 文档、常见代理(Nginx)配置建议