websocket连接在nginx下频繁断开,主因是connection和upgrade请求头未正确配置:必须设connection为"upgrade"、upgrade为$http_upgrade,并配合proxy_http_version 1.1、proxy_read_timeout与proxy_send_timeout超时设置。

WebSocket 连接在 Nginx 反向代理下频繁断开,绝大多数情况是因为协议升级环节没走通——关键就在 Connection 和 Upgrade 这两个请求头是否被正确传递和改写。只配 proxy_pass 或只加 proxy_http_version 1.1 是不够的,必须显式干预这两个头。
为什么必须写死 Connection 为 "upgrade"
Nginx 默认不会透传客户端的 Connection 头,更不会主动把它改成 upgrade。而 WebSocket 协议升级要求服务端收到的请求中,Connection: upgrade 必须存在且值严格匹配(不能是 keep-alive, upgrade 这类组合值)。Nginx 官方文档明确要求:该头必须强制设为字符串 "upgrade",否则后端(如 Node.js、Spring Boot、Tomcat)无法识别升级意图。
- 错误写法:
proxy_set_header Connection $http_connection;—— 客户端可能发keep-alive,后端直接忽略 - 正确写法:
proxy_set_header Connection "upgrade";—— 强制覆盖,确保语义清晰 - 这个配置必须放在
location块内,且紧邻proxy_pass,避免被外层配置覆盖
Upgrade 头要动态取值,不能硬编码
Upgrade 头的值必须是客户端原始请求里的内容(通常是 websocket),不能写成固定字符串。因为浏览器发起 WebSocket 连接时,会自动带上 Upgrade: websocket;如果 Nginx 把它改成其他值(比如 "WebSocket" 或漏掉),后端就收不到标准升级信号。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 正确写法:
proxy_set_header Upgrade $http_upgrade;——$http_upgrade是 Nginx 内置变量,自动提取请求头中的 Upgrade 字段 - 错误写法:
proxy_set_header Upgrade websocket;—— 看似一样,但实际丢失了大小写和空格兼容性,某些客户端可能出问题 - 注意:
$http_upgrade在非 WebSocket 请求中为空,所以这个配置对普通 HTTP 请求无副作用
配套必须开启的三项基础配置
光设好两个头还不够,WebSocket 是长连接,Nginx 默认的超时机制会主动断连。以下三项需同步调整:
-
proxy_http_version 1.1;—— HTTP/1.0 不支持持久连接,升级必然失败 -
proxy_read_timeout 86400;—— 设置读超时为 24 小时(或按业务需要设为 300~3600),防止空闲时被 Nginx 关闭连接 -
proxy_send_timeout 86400;—— 同理,控制发送响应的等待上限,避免握手后因响应延迟被中断
完整 location 示例(推荐直接复用)
假设你的 WebSocket 接口路径是 /ws 或 /api/ws,对应后端服务地址为 http://localhost:8080:
location /ws {<br> proxy_pass http://localhost:8080;<br> proxy_http_version 1.1;<br> proxy_set_header Upgrade $http_upgrade;<br> proxy_set_header Connection "upgrade";<br> proxy_set_header Host $host;<br> proxy_set_header X-Real-IP $remote_addr;<br> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br> proxy_set_header X-Forwarded-Proto $scheme;<br> proxy_read_timeout 86400;<br> proxy_send_timeout 86400;<br>}
配置完记得执行 nginx -t 检查语法,再 nginx -s reload 生效。不复杂但容易忽略。










