为什么 WebSockets 对大多数实时应用来说是大材小用
Source: Dev.to

在构建实时功能时,大家往往会直接使用 WebSocket。实际上,大多数应用只需要单向更新——而 服务器发送事件(SSE) 能以更好、更简洁、更低成本的方式实现这一需求。
下面我们来拆解一下 WebSocket 在什么情况下真正有意义——以及在什么情况下并不适用。
WebSocket 默认问题
“实时”已成为“使用 WebSockets”的代名词。
但这种假设跳过了一个关键问题:
到底是谁在说话?
在大多数真实世界的应用中,答案很简单:
- 服务器 产生更新
- 客户端 监听并渲染
这不是对话,而是流。
然而团队仍然要付出 WebSocket 的代价:
- 更多代码
- 更多状态
- 更难扩展
- 额外的调试痛苦
通常是为了那些从不回传数据的功能。
大多数实时功能的真实样子
这些本质上是单向的
- 仪表盘(指标、分析、监控)
- 通知与警报
- 活动流
- 股票或加密货币行情
- CI/CD 构建状态
- 日志流
- AI 响应流
- 系统健康更新
在所有这些场景中,数据流向为 server → client。
客户端输入(如果有)通过普通的 HTTP 请求完成。这正是 SSE 发光发热的地方。
当 WebSocket 真正重要时
WebSocket 是在以下情况下的正确工具:
- 持续的双向通信
- 客户端驱动的状态变化
- 超低延迟
- 二进制数据传输
示例
- 多人游戏
- 协同编辑器
- 实时交易终端
- 语音/视频信令
这个类别确实存在——只不过比大多数团队想象的要小得多。
什么是服务器发送事件 (SSE)?
SSE 是一种长连接的 HTTP,服务器在事件发生时实时推送更新。无需协议升级、无需自定义帧、也不需要心跳技巧——仅仅是 HTTP。
客户端(浏览器)
const source = new EventSource('/events');
source.onmessage = (e) => {
console.log(JSON.parse(e.data));
};
服务器(Node.js)
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`);
}, 1000);
req.on('close', () => clearInterval(interval));
});
这就是一个可工作的实时流——无需任何库。
为什么 SSE 是更好的默认选择
1. 它只是 HTTP
SSE 运行在标准 HTTP(80/443)上:
- 能在代理后工作
- 能与 CDN 配合使用
- 能在企业网络中使用
- 只要 HTTP 能通,就能通
在受限环境下,WebSocket 往往会悄然失效。
2. 自动重连已内置
如果连接中断:
- 浏览器会自动重新连接
- 并带有退避策略
- 完全不需要你写任何代码
使用 WebSocket 时,重连逻辑 全是你的事。
3. 调试非常简单
想要检查实时数据?
curl -N https://example.com/events
立刻可见。无需特殊工具。
4. 性能几乎相同
在真实系统中:
- 网络延迟占主导
- 数据库延迟占主导
- 渲染时间占主导
协议之间的差异通常只有 毫秒级——对仪表盘、信息流和通知的用户来说几乎不可感知。
5. HTTP/2 消除了旧限制
过去的担忧:“浏览器限制连接数”。
使用 HTTP/2:
- 单一 TCP 连接
- 多路复用多个流
- 实际上没有连接上限
现代浏览器和服务器已经支持这一点。
SSE 的实际应用
AI 流式响应
用户通过 POST 发送提示。服务器流式返回令牌。客户端逐步渲染。不需要双向通道。
可观测性与监控
指标和日志由服务器生成。客户端仅进行监听。SSE 使系统保持简单且可扩展。
功能标志和配置更新
客户端监听变化。它们不进行协商。是 SSE 的理想场景。
当 SSE 不适用时
避免在需要以下情况时使用 SSE:
- 二进制流传输
- 持续的客户端输入
- 子 10 毫秒 延迟保证
- 点对点协商
这时 WebSockets(或 WebRTC)才发挥作用。
常见 SSE 陷阱(已解决)
- 缓冲响应 → 禁用代理缓冲
- 空闲超时 → 发送轻量心跳
- 水平扩展 → 使用 Redis/Kafka 作为后端总线
- 身份验证 → 使用 cookie 或短期令牌
这些都是已解决的问题——不是阻碍。
更好的思维模型
Instead of asking:
“我们需要实时吗?”
Ask:
“谁在说话,谁在倾听?”
If the server does most of the talking, SSE should be your first choice. WebSockets should be intentional, not automatic.
底线
WebSockets 功能强大——但往往并非必需。对于大多数实时功能,服务器发送事件(Server‑Sent Events):
- 更简单
- 更易调试
- 更易扩展
- 更易维护
- 在生产环境中更可靠
枯燥的技术在生产中更受青睐。对于服务器到客户端的流式传输,SSE 是那种枯燥且正确的选择。
讨论
你在应用中如何处理实时功能?是否曾在本可以使用 SSE 的情况下使用了 WebSockets,或反之亦然?欢迎分享你的真实经验。