websocket长连接必须主动心跳,否则nginx(默认proxy_read_timeout=60秒)、运营商nat、防火墙会在30–60秒内静默断开;需客户端定时发ping、服务端及时回pong,并配超时检测与重连逻辑。

WebSocket长连接不能靠“连上就完事”,必须主动发心跳,否则 Nginx、运营商 NAT、防火墙会在 30–60 秒内静默断开连接。核心是:客户端定时发 PING,服务端及时回 PONG,前端配好超时检测与重连逻辑。
为什么 Nginx 后面的 WebSocket 总是 60 秒断?
Nginx 默认 proxy_read_timeout 是 60 秒——只要后端 60 秒没往客户端发任何数据,Nginx 就直接 FIN 断连,且不通知后端。这不是 Bug,是设计如此。你查日志看到 WebSocket disconnected,大概率就是它干的。
- 必须改 Nginx 配置:
proxy_read_timeout 300(建议 ≥ 心跳间隔 × 2) - 同时加
proxy_set_header Connection 'upgrade'; proxy_set_header Upgrade $http_upgrade;,否则压根升不了级 - 如果用的是云厂商 LB(如阿里云 SLB、腾讯云 CLB),还得单独开启“长连接保持”或调高空闲超时,它们默认比 Nginx 更激进(有的仅 30 秒)
FastAPI 后端怎么收心跳并防假在线?
FastAPI 原生不处理 ping/pong 控制帧,得用普通消息模拟。关键不是“收到 PING 就回 PONG”,而是要绑定连接生命周期做超时管理。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 每个
WebSocket实例接收到PING时,更新其最后活跃时间戳(比如存到websocket.state.last_ping_time = time.time()) - 启动一个后台任务(
asyncio.create_task),每 10 秒轮询所有连接,对time.time() - last_ping_time > 90的连接主动close() - 别依赖
on_disconnect回调——网络异常时它根本不会触发;主动探测才是唯一可靠方式 - 示例判断逻辑:
if websocket.application_state == WebSocketState.CONNECTED and time.time() - getattr(websocket.state, "last_ping_time", 0) > 90:
JavaScript 前端心跳定时器容易漏掉哪几件事?
浏览器标签页切到后台、系统休眠、低端安卓机降频,都会让 setInterval 失效或严重延迟,导致心跳包发不出去,连接被中间设备掐断。
- 不要只靠
setInterval发心跳,要用setTimeout链式递归,每次成功发完再设下一次,避免堆积或错乱 - 监听
visibilitychange事件:页面隐藏时暂停心跳,显示时立即补发一次PING并重置超时计时器 -
onmessage收到PONG后必须调clearTimeout当前超时句柄,再setTimeout新的——否则多个定时器并发,一超时就疯狂重连 - 别用字符串
"PING"和"PONG",建议用 JSON:{"type":"ping","ts":1716582345},方便后续加字段、做时间漂移校准
心跳间隔和超时阈值怎么设才不翻车?
设太短(如 5 秒)会白耗带宽、抬高服务器连接数;设太长(如 120 秒)等同于放弃保活——多数 NAT 网关空闲超时就在 90–120 秒之间。
- 推荐组合:
heartbeat_interval = 30000(30 秒发一次),timeout_threshold = 60000(60 秒没回就断) - 必须满足:
heartbeat_interval × 2 ,例如阿里云 SLB 默认 90 秒,那心跳就得 ≤ 40 秒 - 服务端主动断连阈值(如 FastAPI 后台轮询判定)应设为
heartbeat_interval × 3,留出网络抖动余量 - 移动端尤其注意:iOS Safari 对后台 tab 的定时器限制极严,实测 30 秒心跳在锁屏后 2 分钟内必断,需配合 Service Worker 或 background fetch(但兼容性差),最稳还是靠快速重连
真正难的不是写心跳代码,而是把 Nginx、LB、服务端空闲检测、前端 visibility 状态、重连退避策略全串成一条链。漏掉任意一环,连接都会在某个角落安静消失。










