nginx不处理websocket心跳,仅透传ping/pong帧、维持连接、禁用缓冲;需配置升级头透传、延长超时(proxy_read_timeout等设为86400)、关闭缓冲与压缩,并配合前后端25–30秒心跳协同保活。

Nginx 本身不生成、不响应 WebSocket 的心跳(Ping/Pong 帧),它的作用是**透传心跳、维持连接不被误杀、避免帧流被缓冲或截断**。真正的心跳检测必须由前后端协同完成,Nginx 只是关键的“保活通道”。配置核心就三件事:升级头透传、超时调大、缓冲关掉。
确保 WebSocket 握手成功(升级头不能丢)
握手失败,心跳根本无从谈起。Nginx 默认会丢弃 Upgrade 和 Connection 这两个逐跳头,必须显式放行:
- proxy_http_version 1.1; —— HTTP/1.0 不支持协议升级,缺了这句会静默降级
-
proxy_set_header Upgrade $http_upgrade; —— 用变量转发客户端原始值(如 websocket),不能硬写
"websocket" -
proxy_set_header Connection "upgrade"; —— 必须是带英文双引号的字面量
upgrade,不是$http_connection(它常为 keep-alive)
这三行必须放在 location 块内(比如 location /ws/ { }),server 或 http 块顶层写无效。
延长超时时间,防止 Nginx 主动断连
WebSocket 是空闲长连接,Nginx 默认 proxy_read_timeout 60s:只要后端 60 秒没向客户端发数据,它就直接 FIN 断开——前端看不到错误,只看到“突然掉线”。解决方法是设为远大于心跳间隔:
- proxy_read_timeout 86400; —— 推荐设为 24 小时(86400 秒),覆盖任意业务场景(最关键)
- proxy_send_timeout 86400; —— 防止后端推送大消息或响应慢时被中断
- keepalive_timeout 86400; —— 保持客户端到 Nginx 的 TCP 连接存活,与上游对齐更稳妥
注意:proxy_read_timeout 控制 Nginx 等待后端数据的时间;keepalive_timeout 对 WebSocket 有效,别信“它没用”这种过时说法。
关闭缓冲与干扰机制,保证心跳帧实时透传
WebSocket 数据是连续帧流(TEXT/BINARY/PING/PONG),Nginx 默认缓冲和 Nagle 算法会导致粘包、延迟甚至丢帧:
-
proxy_buffering off; —— 关在
location块里,禁用响应缓冲,避免帧被攒包 - proxy_cache off; —— 显式禁用缓存,否则 Upgrade 请求可能被缓存命中返回 200
- tcp_nodelay on; —— 绕过 Nagle 算法,小帧(如光标移动、VAD 触发)立即送达
- gzip off; 和 proxy_set_header Accept-Encoding ""; —— 避免压缩干扰二进制帧
不要用 sub_filter、proxy_redirect 或任何可能改写响应体的操作,它们会破坏 Ping/Pong 帧结构。
配合前后端心跳,形成闭环保活
Nginx 不处理 ping/pong,但它是心跳链路上的关键一环:它得把客户端 PING 透传给后端,再把后端 PONG 原样送回;同时自身超时不能早于心跳周期,否则还没等服务端响应,连接已被 Nginx 关闭:
- 前端应使用
setTimeout链式递归发心跳,避免setInterval在后台冻结失效 - 服务端收到 PING 后需立即响应 PONG,并更新该连接的最后活跃时间戳
- 心跳间隔建议设为 25–30 秒,必须严格小于
proxy_read_timeout - 服务端不维护心跳计时器,只依赖客户端行为和连接关闭事件清理资源
验证是否生效,需结合后端日志与抓包分析(如 tcpdump 过滤 opcode=9/10),仅靠 Nginx 日志无法确认 Ping/Pong 是否真实穿透。











