07 · WebSocket 与长连接
聊天、推送、协同编辑都要"服务端主动推数据",HTTP 请求-响应模型做不来,于是有 WebSocket。本篇讲握手升级、心跳、断线重连与上线三件套;API 层比较见 C02 API 设计。
速览卡
| 项 | 内容 |
|---|---|
| 一句话定位 | 全双工长连接的原理与工程落地 |
| 核心内容 | 握手升级、帧与消息、心跳保活、断线重连、负载均衡注意 |
| 读完能回答 | WebSocket 和 HTTP 什么关系?为什么必须心跳? |
| 相关板块 | N04 HTTP | N09 代理与网关 | N12 IO 模型 |
一、为什么需要它
text
HTTP 轮询:客户端反复问"有新消息吗"
WebSocket:连一次,之后服务端随时推| 对比 | 轮询 | WebSocket |
|---|---|---|
| 实时性 | 有延迟 | 即时 |
| 连接数 | 每次请求都建连 | 一条长连接 |
| 方向 | 客户端发起 | 双向 |
二、握手:一次 HTTP 升级
text
客户端 ── GET 带 Upgrade: websocket ──> 服务端
服务端 <── 101 Switching Protocols ──── 客户端
之后切换为 WebSocket 帧协议WebSocket 不是独立协议,而是 HTTP 的升级:先走一次 HTTP 握手,成功后换成全双工帧。所以端口、TLS、代理规则都复用 HTTP 基础。
三、消息与帧
| 概念 | 说明 |
|---|---|
| 帧 | 传输基本单位(文本 / 二进制 / 控制帧) |
| 消息 | 业务上的一整条数据,可能分多帧 |
| 控制帧 | ping / pong / close |
四、心跳保活:为什么必须有
text
空闲连接可能被中间设备静默杀掉
定期 ping / pong → 发现死连接 → 触发重连心智模型:长连接像一根长期占用的电话线,中间交换机可能悄悄挂断却不通知你;心跳就是定期"喂,还在吗"。
五、断线重连与上线三件套
text
① 指数退避重连(别把服务端打爆)
② 心跳失败判定 → 主动断开
③ 重连后做状态恢复(补消息 / 重订阅)上线 WebSocket 至少要做三件事:鉴权(握手带凭证)、心跳、重连补发。少一件,线上就会出"看似在线实则断线"的诡异问题。
六、服务端注意:负载均衡与长连接
| 场景 | 风险 | 对策 |
|---|---|---|
| 多实例 | 连接散在不同节点 | 按连接做亲和 / 用消息总线广播 |
| 代理层 | 空闲超时杀掉连接 | 调长代理超时或改走专用网关 |
| 连接数 | 每条连接占一个 fd 与内存 | 参考 N12 IO 模型 |
七、自检清单
- [ ] 能画出 WebSocket 的 HTTP 升级握手
- [ ] 能说清为什么需要心跳
- [ ] 能列出断线重连的三要素
- [ ] 知道多实例部署时长连接会踩什么坑
- [ ] 能判断该用 WebSocket 还是 SSE/轮询
八、常见误区
| 误区 | 事实 |
|---|---|
| "WebSocket 和 HTTP 无关" | 握手本身就是 HTTP 升级 |
| "有连接就不用心跳" | 空闲连接会被中间设备静默杀掉 |
| "重连越快越好" | 要指数退避,避免重连风暴 |
| "加个 WebSocket 就完事" | 鉴权、心跳、补发缺一不可 |
九、动手练习
练习 A:看一次握手
DevTools → Network,找到 WebSocket 请求,观察 101 Switching Protocols 与帧面板。
练习 B:实现最小聊天
用 Node ws 或 Python websockets 写一个 echo 服务,前端连上收发消息,观察连接状态。
练习 C:做断线重连
在练习 B 基础上加心跳与指数退避重连,人为断开网络观察重连行为。
相关文档
本区
- 04 · HTTP 与 HTTPS 深入 —— 握手的 HTTP 基础
- 09 · 代理与反向代理与API网关 —— 网关与长连接
- 12 · 网络编程IO模型 —— 服务端高并发底座
其他域
- API 设计:REST / gRPC / GraphQL —— 长连接与 API 风格选择
- 异步与消息:消息队列/事件驱动 —— 推送事件的另一种承载