14. WebSocket 原理及与 SSE、轮询的对比(热度 572 / 365 · 核心必考)
Q: WebSocket 的原理?和 SSE、HTTP 轮询有什么区别?实时聊天为什么选 WebSocket?
A:
WebSocket 原理(握手 + 帧)
- HTTP 升级握手: 客户端带
Upgrade: websocket、Connection: Upgrade、Sec-WebSocket-Key、Sec-WebSocket-Version: 13;服务器回 101 Switching Protocols 与Sec-WebSocket-Accept(由 Key 与固定 GUID 计算)。 - 协议切换: 此后在同一 TCP 上走 WebSocket 帧协议,不再是 HTTP 请求/响应模型。
- 帧与语义: 文本/二进制/Close/Ping/Pong/连续帧;客户端→服务器帧必须掩码,服务器→客户端不掩码;支持分片与扩展(如 permessage-deflate)。
- 保活与关闭: Ping/Pong 心跳;Close 帧携带状态码。
- 安全: 生产常用
wss://(WebSocket over TLS,对应 443)。
与 SSE、轮询对比
| 方案 | 方向 | 协议基础 | 开销 | 适用 |
|---|---|---|---|---|
| 短轮询 | 客户端拉 | HTTP 定时请求 | 高(大量空请求) | 低频、简单 |
| 长轮询 | 客户端拉 | HTTP 挂起直到有数据 | 中 | 准实时、兼容要求高 |
| SSE | 服务器单向推 | HTTP text/event-stream | 低 | AI 流式输出、进度、行情 |
| WebSocket | 双向全双工 | 独立帧(HTTP 升级) | 最低(长连接) | 聊天、协同编辑、游戏 |
为何聊天选 WebSocket: 需要双向高频(消息、回执、在线状态);轮询延迟高浪费连接;SSE 单向上行仍要另发 HTTP。WS 一条长连接双向即发即达。
设计动机: 先走 HTTP 可复用 80/443、穿透代理并利用 TLS;SSE 天然 HTTP、自动重连但单向;WebSocket 为高效双向帧而离开 HTTP 模型。
常见追问
追问 1:WebSocket 和 SSE 怎么选?
- 答题要点: 只要服务器→客户端单向流(LLM token、进度、通知)→ SSE 更简单、HTTP 生态好;要双向、高频、低延迟(聊天、协同、游戏)→ WebSocket。很多产品上行 REST/下行 SSE。
追问 2:WebSocket 如何保活?断线怎么办?
- 答题要点: 协议层 Ping/Pong 或应用层心跳;断线后客户端指数退避重连,服务端需会话恢复(uid/token、消息序号、补拉离线)。
追问 3:负载均衡/LB 对 WebSocket 有什么影响?
- 答题要点: 需支持长连接与 HTTP Upgrade;粘性会话(IP hash 或连接级)有助于避免会话被打散;注意超时配置(idle timeout)要大于心跳周期;nginx
proxy_read_timeout等需调大。
易错点
| 易错说法 | 纠正 |
|---|---|
| 「WebSocket 每次还是 HTTP 请求」 | 仅握手是 HTTP;之后是 WebSocket 帧 |
| 「SSE 是双向的」 | SSE 是服务器→客户端单向 |
| 「WebSocket 不走 TLS」 | wss:// 走 TLS,生产几乎必备 |
| 「轮询比 WebSocket 简单就一定更优」 | 高实时场景轮询成本与延迟都差 |
| 「101 就是成功业务响应」 | 101 仅表示协议升级成功,不是业务状态码 |
与选择题对照
- 主库 150: 第 84 题(HTTP 特点与方法)、第 92 题(HTTP 演进,对比实时方案)、第 145 题(keep-alive/长连接)、第 93 题(应用层协议归属)。选择题库对 WebSocket 覆盖较少——本考点以面试为主。
- 补题 16: 无直接 WebSocket/SSE 题。
- 口述联动: 若被问「101 是什么」,回扣状态码题(第 9 题)+ 本题协议升级。
工程 / 抓包背景
- Wireshark: 过滤
websocket;握手可见Upgrade: websocket与 101。 - 浏览器: DevTools → Network → WS 帧(发送/接收/握手头)。
- Nginx 反代 WebSocket:nginx
location /ws/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } - curl 测握手: 带 Upgrade 头发请求,观察是否 101(完整帧测试需 wscat 等工具)。
- SSE:
curl -N https://api.example.com/stream;响应Content-Type: text/event-stream。