Nginx 反向代理 WebSocket 断连排查
我的 WebSocket 服务挂在 Nginx 后面,连上之后大概一分钟就会自动断开,直连后端没问题。这是什么原因?
“直连正常、过 Nginx 约 60 秒断开”几乎可以确定是 Nginx 的 proxy_read_timeout。它的默认值正好是 60 秒:如果这段时间内上游没有发来任何数据,Nginx 就会关闭连接。
WebSocket 连接空闲时不传数据,所以会撞上这个超时。
那我应该怎么配?
需要做两件事:一是正确转发 Upgrade 握手,二是调大读写超时。一份可用的配置如下:
nginx
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name chat.example.com;
location /ws/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 空闲超过这个时间才会断开;配合应用层心跳使用
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
几点说明:
proxy_http_version 1.1必须写,默认的 1.0 不支持 Upgrade。map让普通 HTTP 请求也能走同一个 location,不会被强行加上Connection: upgrade。- 超时调大只是兜底,更稳的做法是客户端每 30 秒发一次 ping。
前面还有一层云厂商的负载均衡,会不会也有超时?
会。负载均衡通常有自己的“空闲超时”,常见默认值是 60 秒或 350 秒。整条链路的实际超时取最短的那一段,所以 LB、Nginx、应用三层都要检查。
最省心的办法仍然是心跳:只要间隔小于链路上最短的超时,连接就不会因为空闲被断。
心跳间隔设多少合适?
取链路最短超时的一半左右。比如最短是 60 秒,就设 25–30 秒。太短会白白增加流量和服务器负担,移动端还会更耗电。
改完之后怎么验证?
- 执行
nginx -t检查语法,再nginx -s reload。 - 先关掉客户端心跳,用
websocat wss://chat.example.com/ws/连上后保持空闲,看是否还在 60 秒时断开。 - 确认不断之后再打开心跳,观察几小时的连接时长。
好的,已经不断了,谢谢!
不客气。后面如果遇到别的问题,比如部署后连接数突然变多,可以把 Nginx 的 error log 发给我一起看。
回复由 AI 生成,可能有误,请核对重要信息。