要让nginx正确代理websocket并实现稳定长连接,关键是透传upgrade和connection头、设proxy_read_timeout和proxy_send_timeout≥心跳间隔、关闭proxy_buffering与proxy_cache、启用tcp_nodelay,并确保前后端心跳协同。

要让 Nginx 正确代理 WebSocket 并实现稳定长连接,关键不是“开启 WebSocket”,而是让整个链路适配其全双工、低延迟、依赖心跳的本质——Nginx 本身不生成或响应 ping/pong,但它必须透传、不干扰、不误杀。
必须透传升级头,握手才能成功
WebSocket 握手是一次 HTTP 升级请求,Nginx 若过滤或改写关键头部,后端收不到信号,就会返回 200 而非 101,连接直接失败:
- proxy_http_version 1.1; —— HTTP/1.0 不支持 Upgrade,缺了这句握手必断
- proxy_set_header Upgrade $http_upgrade; —— 把客户端原始值(如 websocket)原样转发,不能硬编码
- proxy_set_header Connection "upgrade"; —— 必须是带英文双引号的字面量 upgrade,不能写成 $http_connection(可能含 keep-alive)
超时设置要远大于心跳间隔
Nginx 默认 proxy_read_timeout=60 秒,只要后端 60 秒没向客户端发数据,它就主动 FIN 断连——这不是故障,是默认资源策略。心跳间隔若为 30 秒,超时至少设为 90 秒以上才安全:
- proxy_read_timeout 86400; —— 控制 Nginx 等待后端数据的最大时间,建议设为 24 小时(或按业务最长会话设定)
- proxy_send_timeout 86400; —— 防止推送大消息或慢响应时被中断
- keepalive_timeout 86400; —— 保持客户端到 Nginx 的 TCP 连接存活,与上游对齐更稳妥
关闭缓冲与禁用缓存,避免帧流被破坏
WebSocket 数据以帧为单位实时双向流动,Nginx 默认缓冲机制会导致粘包、延迟甚至乱序,尤其在音视频或高频消息场景下明显:
- proxy_buffering off; —— 必须放在 location 块内,不可全局启用
- proxy_cache off; —— 显式禁用缓存,防止 Upgrade 请求被命中返回 200
- tcp_nodelay on; —— 绕过 Nagle 算法,小帧(如光标移动、VAD 触发)立即送达
配合前后端心跳,形成闭环保活
Nginx 不处理 ping/pong,但它是心跳链路上的关键一环:它得把客户端 PING 透传给后端,再把后端 PONG 原样送回;同时自身超时不能早于心跳周期,否则还没等服务端响应,连接已被 Nginx 关闭:
- 前端应使用 setTimeout 链式递归 发心跳,避免 setInterval 在后台冻结失效
- 服务端收到 PING 后需立即响应 PONG,并更新该连接的最后活跃时间戳
- 服务端另起任务定期检查所有连接,若 last_heartbeat 超过阈值(如心跳间隔 × 2),主动 close()
- 云厂商 LB(如阿里云 SLB)默认空闲超时仅 30–60 秒,需单独调高,否则 Nginx 配置再好也白搭











