websocket在nginx下1分钟断开主因是默认proxy_read_timeout=60秒,它控制nginx从后端读数据的空闲等待时长;需同步配置proxy_http_version 1.1、proxy_set_header upgrade $http_upgrade、proxy_set_header connection "upgrade"、proxy_send_timeout及系统tcp参数,且proxy_read_timeout应设为后端心跳间隔的2–3倍(如90–120秒),不可设0。

WebSocket连接在Nginx下1分钟断开,基本就是proxy_read_timeout卡在默认60秒——它不是“总连接时长”,而是“两次读之间最多等多久没数据”。设成60s,后端只要静默超60秒(比如心跳漏发、网络抖动、服务GC暂停),Nginx就直接关TCP连接,前端收到EOFException或close event。
为什么改了proxy_read_timeout还是断?
单改这个参数几乎必然失效,因为Nginx代理WebSocket是“四件套”协同工作:
-
proxy_http_version 1.1缺失 → 后端收不到Upgrade头,握手失败(400/502) -
proxy_set_header Upgrade $http_upgrade写成"websocket"→ 非标准客户端(如某些IoT设备)的Upgrade: h2c被硬覆盖,升级中断 -
proxy_set_header Connection "upgrade"写成$connection→ 变成Connection: close,连接立刻断 - 没配
proxy_send_timeout→ 后端发大消息分片慢,Nginx在发送中途就切断,比proxy_read_timeout还早触发
proxy_read_timeout该设多少才不瞎调?
值必须对齐你后端的真实心跳节奏,不是拍脑袋填86400:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 后端每30秒发一次
ping→proxy_read_timeout设90~120(2–3倍,留抖动余量) - 设备上报周期45秒 → 设
180(别用180整数倍,避开60秒共振陷阱) - 低频通知通道(审批、邮件)→
3600足够,再大只会延迟故障暴露 - 绝对不要设
0→ 僵死连接会吃光upstream连接池,且内核tcp_keepalive_time仍会踢人
Kubernetes Ingress里怎么正确覆盖?
Ingress Controller不认nginx.conf里的全局配置,硬改会被升级覆盖,且无法按路由区分:
- 注解key必须是
nginx.ingress.kubernetes.io/proxy-read-timeout(带连字符,不是下划线) - 值必须是字符串,带英文引号:
"3600",单位是秒,不是毫秒 - 必须同步加
nginx.ingress.kubernetes.io/proxy-send-timeout:"3600",否则单向超时 - Helm部署时,这些要写进
values.yaml的annotations字段,不是extraArgs
最常被忽略的是系统级TCP参数:如果net.ipv4.tcp_keepalive_time设成600(10分钟),而proxy_read_timeout设了3600,内核会在Nginx之前主动发FIN包——这时候日志里看不到Nginx超时记录,但连接就是断了。










