websocket在nginx代理下出问题主因是未正确识别协议,需强制http/1.1、透传upgrade/connection头、隔离http/2干扰、调优超时与缓冲、确保路径匹配一致。

WebSocket 在 Nginx 代理下出问题,往往不是协议本身不兼容,而是 Nginx 没“认出”它是 WebSocket —— 它仍按普通 HTTP 请求处理,导致升级失败、连接闪断或 502/403 错误。核心在于强制走 HTTP/1.1 路径、透传关键头部、隔离 HTTP/2 干扰,并匹配后端真实行为。
必须显式启用 HTTP/1.1 升级机制
WebSocket 握手依赖 HTTP/1.1 的 Upgrade 和 Connection: upgrade 头,HTTP/2 已废弃该机制,因此:
- proxy_http_version 1.1; —— 必须写死,不能是 1.0 或 2.0;
- proxy_set_header Upgrade $http_upgrade; —— 变量仅在客户端带 Upgrade 头时生效,安全可靠;
- proxy_set_header Connection "upgrade"; —— 注意双引号,这是指令而非变量引用;
- 若前端用 HTTPS + HTTP/2(如
listen 443 ssl http2),这些头可能被 ALPN 协商静默丢弃,需单独隔离。
隔离 HTTP/2 干扰的实用方案
主站用 HTTP/2 提升网页性能,但 WebSocket 流量必须绕开它。推荐做法是路径或域名级分离:
-
子域名隔离(最稳妥):配
ws.example.com独立 server 块,listen 443 ssl;不加http2; -
路径级分流(适合轻量场景):用
map判断$http_upgrade,动态指向不同 upstream; - 避免 if + return 302:重定向会破坏 WebSocket 握手的原子性,极易失败;
- 不建议强行在 HTTP/2 server 内“降级”,Nginx 无法在 h2 连接上触发 Upgrade 流程。
超时与缓冲必须针对性调优
WebSocket 是长连接,Nginx 默认配置会把它当成短请求中途掐断:
- proxy_read_timeout 86400; —— 设为大于后端心跳间隔(如后端 ping/pong 30 秒,则至少设 60 秒以上);
- proxy_send_timeout 86400; —— 防止大消息分片发送被中断;
- proxy_buffering off; —— 否则帧数据会被缓存,破坏实时性,引发“毛刺”;
- gzip off; —— WebSocket 帧不可压缩,开启 gzip 可能导致解析错乱;
- client_max_body_size 0; 和 client_body_timeout 0; —— 避免 Nginx 尝试读取无意义的二进制帧体。
路径与后端对接要严格一致
location 匹配和 proxy_pass 路径稍有偏差,就会导致 Upgrade 请求发到错误路径,后端收不到或返回 404/403:
- 用前缀匹配如
location /ws/ { ... },确保前端连wss://example.com/ws/xxx时路径完整透传; -
proxy_pass末尾带斜杠(http://backend/ws/)比不带更可控,避免 Nginx 自动截断重写; - 若后端监听
/ws,而 Nginx 写成location /ws { proxy_pass http://backend; },实际转发路径可能是/,造成升级失败; - 禁用 rewrite 或复杂正则,除非你完全掌控捕获组与路径拼接逻辑。











