web游戏websocket频繁断开主因是nginx默认proxy_read_timeout=60秒静默断连,需同步配置proxy_http_version 1.1、proxy_set_header upgrade $http_upgrade、proxy_set_header connection "upgrade"、proxy_read_timeout 86400、proxy_send_timeout 86400、proxy_buffering off、proxy_cache off,并配合系统tcp参数与客户端心跳机制。

Web 游戏用 WebSocket 实时同步状态,一旦连接频繁断开,玩家会卡顿、掉线、操作丢失——问题往往不出在游戏逻辑,而是 Nginx 把连接“静默杀掉”了。核心原因就是 proxy_read_timeout 仍用默认的 60 秒:只要后端 60 秒内没发任何数据(比如心跳漏了、服务 GC 暂停、网络抖动),Nginx 就直接发 RST 关 TCP,前端只收到 code 1006,无日志、无错误提示,极难定位。
确认是不是 proxy_read_timeout 在作怪
别猜,先验证:
- 看断开时间是否集中在 60±2 秒(如 21:13:41 连上 → 21:14:42 断开);
- 浏览器 DevTools → Network → WS 标签,点开连接,检查响应头是否含 HTTP/1.1 101 Switching Protocols;如果看到 200、403 或 502,说明握手失败,不是超时问题;
- 客户端监听
onclose,打印event.code:若大量为 1006,基本可锁定是代理或系统层强制中断。
必须改的 Nginx 配置项(四件套+超时)
仅调大 proxy_read_timeout 不够,缺一不可:
安全更新和维护 CLI Proxy API(CPA)部署与配置。用于 CPA 镜像升级、配置变更、认证目录兼容修复、上线验证与回滚。适用于用户提到“CPA 更新/升级/配置改了/容器重建/回滚”等场景。
- proxy_http_version 1.1:HTTP/1.0 不支持 Upgrade,不写这行,WebSocket 握手直接失败;
-
proxy_set_header Upgrade $http_upgrade:变量名必须是
$http_upgrade,写成$upgrade或硬填"websocket"都会导致升级失败; -
proxy_set_header Connection "upgrade":双引号不能少,值必须是字面量
"upgrade",写成$connection或带空格会变Connection: close; - proxy_read_timeout 86400:设为 24 小时(秒),远大于你的心跳间隔 ×2(如心跳 30 秒,这里至少 90,但生产建议设大些防抖动);
- proxy_send_timeout 86400:同样设长,避免客户端发心跳时 Nginx 等不及响应就切断;
- proxy_buffering off; proxy_cache off;:防止消息被缓存延迟或丢帧,对实时性要求高的 Web 游戏很关键。
别漏掉系统级和客户端配合
Nginx 配好了,还可能被底层掐断:
- 检查服务器
net.ipv4.tcp_keepalive_time,若设为 600(10 分钟),而proxy_read_timeout设了 3600,内核会在 Nginx 之前发 FIN —— 此时 Nginx 日志里查不到超时记录; - Web 游戏客户端必须实现心跳:每 25–30 秒发一次 ping,服务端收到后回 pong;服务端也要校验连续两次未收到 ping 才关闭连接;
- 移动端(尤其 iOS Safari / WKWebView)切后台时 JS 定时器会冻结,需用
Page Visibility API检测页面可见性,切后台时主动重连或暂停心跳,避免 NAT 超时后静默断连。
Kubernetes Ingress 或云负载均衡注意点
如果用的是 Ingress 或 AWS ALB/Traefik:
- Ingress 注解要写全:
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"(注意是连字符、英文引号、单位秒); - AWS ALB 不支持调大空闲超时(固定 4000 秒上限且不可改),只能把心跳压到 ≤ 30 秒,并确保服务端快速响应;
- Traefik 对应配置是
traefik.http.routers.myws.middlewares+ 自定义 middleware 设置 idle timeout。










