Nginx反向代理下WebSocket60秒断连是因默认proxy_read_timeout=60s误杀长连接,需在location块中配置proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade与Connection "upgrade"、proxy_read_timeout 3600,并关闭proxy_buffering和gzip。

WebSocket 在 Nginx 反向代理下运行约 60 秒后断开,不是代码缺陷,而是 Nginx 默认 proxy_read_timeout 60s 主动终止了空闲连接——它把合法的长连接当成了“僵死连接”,直接发 FIN 包中断,后端甚至来不及响应。这个行为会触发客户端 1006 unexpected EOF、WebSocket is closed before the connection is established 等错误,日志中常见 upstream prematurely closed connection。
必须在 location 块里加的三项核心配置
这些不能写在 http 或 server 级,必须精准落在 WebSocket 路径(如 location /ws/ { ... })内:
-
启用 HTTP/1.1 协议升级基础:添加
proxy_http_version 1.1;。HTTP/1.0 不支持 Upgrade 机制,缺了这行,握手从第一步就失败 -
透传协议升级信号:加上
proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade";(注意双引号)。漏掉任意一个,后端收不到Upgrade: websocket和Connection: Upgrade,就会返回 400/502,而不是预期的 101 -
延长读超时时间:显式设置
proxy_read_timeout 3600;(建议至少 3600,即 1 小时)。该值控制 Nginx 等待后端数据的时间,不是连接总寿命,但空闲保活全靠它撑住
配套关闭干扰项,防止帧错乱与延迟
只改超时不够,Nginx 的默认缓冲和压缩策略会破坏 WebSocket 的流式帧结构:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
-
关闭响应缓冲:添加
proxy_buffering off;。否则 Nginx 会攒多个小帧一起发,导致客户端收到粘包或乱序数据,gorilla/websocket 解析失败 -
同步发送超时:设
proxy_send_timeout 3600;,与读超时一致。避免服务端响应慢(如大消息推送)被误判为异常而中断 -
禁用 gzip 压缩:加入
gzip off;。WebSocket 帧是二进制流,gzip 会破坏帧边界,引发解析错误或静默丢帧
验证是否真正生效的三个硬指标
重启 Nginx 后,别只看“能连上”,要盯住底层握手和行为:
- 浏览器 Network 面板中,WebSocket 请求的 Status 必须是
101 Switching Protocols,不是 200、403 或 502 - 检查请求头含
Upgrade: websocket和Connection: Upgrade;响应头含Upgrade: websocket和Connection: upgrade - 执行
tail -f /var/log/nginx/error.log,搜索upstream prematurely closed connection—— 出现即说明配置未生效,连接仍在被强制切断
前后端协同保活,绕过中间网络设备
Nginx 配置只是起点,真实链路还经过云 LB、NAT 网关等中间设备,它们常设 30–90 秒空闲超时:
- 前端心跳节奏要激进:建议每 25 秒发一次 ping,留足网络抖动余量。不要依赖 Nginx 的 3600s 就完全不发心跳
- 后端需正确响应:Go 中用
conn.SetPingHandler()自动回 pong;Java Spring 需配setHeartbeatValue;确保 pong 在 3 秒内返回 - 若仍不稳定,检查 upstream 是否配置了
keepalive连接池,避免复用已失效的旧连接引发状态错乱










