在《前端视角下的网络协议》系列中,我们讨论的几乎都是“请求-响应”模式。但在实时聊天、金融看板或 AI 大模型输出场景下,这种模式会显得非常被动。
为了实现服务器主动向前端推送数据,我们需要建立长连接。作为全栈开发者,面对 WebSocket 和 SSE,你不仅要会写代码,更要理解它们在协议层面的差异以及在生产环境中的运维成本。
一、 WebSocket:全双工的“双向奔跑”
WebSocket 是一个独立于 HTTP 的协议,它实现了浏览器与服务器之间的全双工通信。
1. 握手与升级(Upgrade)
WebSocket 的连接始于一个标准的 HTTP 请求。浏览器通过在 Header 中加入 Upgrade: websocket 告知服务器:“我想换个协议”。
- 101 Switching Protocols:一旦服务器同意,TCP 连接将保持开启,双方从此进入 WebSocket 的二进制/文本帧交互。
2. 核心优势
- 真正的双向性:客户端和服务器可以同时互发消息,延迟极低。
- 协议头极小:建立连接后,数据帧的头部开销远小于 HTTP。
3. 运维痛点
- 不兼容 HTTP 代理:某些旧的防火墙或负载均衡器(LB)无法识别这种协议切换。
- 状态维护:服务器需要维护成千上万个持久的 TCP 连接,对内存和并发处理能力有极高要求(参见 Node.js 篇中的
UV_THREADPOOL_SIZE调优)。
二、 SSE (Server-Sent Events):单向的“顺风车”
SSE 并不是一种全新的协议,它是基于 HTTP 协议的一项技术(通常是 text/event-stream 内容类型)。
1. 协议特征
- 单向推送:只有服务器能推给客户端,客户端想说话还得另发 HTTP 请求。
- 打字机效果的福音:因为它是基于流(Streaming)的,非常适合 ChatGPT 这种逐字输出的场景。
2. 核心优势
- 轻量级:原生支持断线重连(
retry机制),无需像 WebSocket 那样手写重连逻辑。 - 兼容性强:它就是标准的 HTTP 请求,能轻松穿过任何防火墙、代理和 Nginx。
- 开发成本低:在 Node.js 中只需设置几个 Response Header 即可。
三、 硬核对比:该选哪一个?
| 维度 | WebSocket | SSE |
|---|---|---|
| 通讯模式 | 全双工 (双向) | 单向 (服务器 -> 客户端) |
| 底层协议 | WebSocket (从 HTTP 升级) | 纯 HTTP |
| 重连机制 | 需要开发者手动实现 | 浏览器原生内置支持 |
| 最大连接数 | 受限于服务器内存和端口 | 受浏览器限制(HTTP/1.1 只有 6 个,HTTP/2 无限) |
| 数据格式 | 支持二进制和文本 | 仅支持 UTF-8 文本 |
四、 生产环境的运维实战
作为 8 年全栈,上线长连接应用时,你必须解决以下两个问题:
1. 代理层的“断连”陷阱
-
Nginx 超时:默认情况下,Nginx 可能会切断长时间没有数据往来的连接。
- 对策:设置
proxy_read_timeout。同时在应用层实现心跳机制(Heartbeat) ,每隔 30 秒发一个 Ping/Pong 包,告诉 Nginx“我还活着”。
- 对策:设置
-
HTTP/2 的多路复用:如果你使用 SSE,务必开启 HTTP/2。否则,一个 SSE 连接会占满 6 个并发连接中的一个,导致页面其他资源加载受阻。
2. 水平扩展与消息分发
当你的 Node.js 服务有多个副本时,客户端 A 连在 Server 1,客户端 B 连在 Server 2。Server 1 怎么把消息发给 B?
- 解决方案:引入 Redis Pub/Sub。服务器接收到推送请求后,先发给 Redis 频道,所有订阅了该频道的服务器副本再寻找自己名下的客户端进行推送。
💡 前端开发者的硬核贴士
- AI 场景选 SSE:如果只是做聊天机器人输出,不要用 WebSocket,SSE 的性能更优且开发极简。
- 双向交互选 WebSocket:如实时多人协作编辑(类似 Google Docs)或高频交易系统。
- 不要忘记
Close:在页面销毁(onUnmounted)时,务必手动关闭长连接,否则会造成严重的服务器连接泄漏。
结语
长连接协议将 Web 应用从“静态拉取”推向了“实时响应”。理解了 WebSocket 的力量与 SSE 的简洁,你才能在复杂的业务需求中选出性能最优、成本最低的通信方案。