他的回复:
先说结论:你贴的这段配置方向是对的,Upgrade、Connection、proxy_http_version 1.1 三件套都齐了,所以 400/502 大概率不是缺这一对头,而是缺 Host 与真实 IP 头、长连接超时没放开,或者实际生效的配置与你看的不是同一份。按下面顺序排查,改一处、验证一处。1. Upgrade 和 Connection 必须成对出现WebSocket 握手是 HTTP 升级机制:客户端发 Upgrade: websocket,Nginx 必须原样把 Upgrade 转给后端,同时把 Connection 置为 upgrade,后端才回 101 Switching Protocols。只写 Upgrade 不写 Connection,后端会当成普通 HTTP 请求处理,多半直接 400;只写 Connection 不写 Upgrade,后端收不到升级意图,同样握手失败。更稳妥的写法是用 map,避免非 WebSocket 请求也被硬改 Connection:map $http_upgrade $connection_upgrade { default upgrade; '' close;}location 里写 proxy_set_header Connection $connection_upgrade; 这样普通请求走 close,握手请求走 upgrade,互不干扰。2. Host、X-Real-IP、X-Forwarded-For 缺失的影响这三行建议都补上:proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;Host 缺失最容易出 400:很多后端按 Host 做虚拟主机或 Origin 校验,收到的 Host 是 127.0.0.1:8080 就直接拒绝,而直连时 Host 正常,所以绕过 Nginx 反而能通。X-Real-IP 与 X-Forwarded-For 缺失一般只影响日志和限流统计,不会直接导致 400,但排查时没有真实 IP 会很难定位,仍建议补齐。3. proxy_http_version 1.1 是必须的Nginx 默认 proxy_http_version 是 1.0,而 HTTP/1.0 不支持 Upgrade 升级语义,握手会在“发了升级请求、后端却不认升级”这一步卡住,表现为 400 或连接直接断开。你已写了 1.1,这一点没问题,但要确认它的生效:执行 nginx -T 看最终合并后的配置,确认没有其他 location 或正则 location 覆盖了 /ws/,也确认改完是 reload 而不是只改了文件没生效。4. 400 与 502 分开查400 优先查请求头转发:用下面第 5 点的方法确认后端实际收到的 Upgrade、Connection、Host 是否齐全,同时看后端日志里拒绝原因是不是 Host、Origin 或 Sec-WebSocket-Protocol 不匹配(如果业务用了子协议,Nginx 还要透传 Sec-WebSocket-Protocol,不能丢)。502 优先查后端可达性与超时:先确认 127.0.0.1:8080 本机端口确实在监听、后端进程没挂;再看 Nginx error_log 里是 connection refused、timeout 还是 upstream prematurely closed。WebSocket 是长连接,默认的 proxy_read_timeout 60 秒很容易在空闲时断连,建议放开:proxy_read_timeout 3600s;proxy_send_timeout 3600s;另外注意 proxy_pass 的斜杠语义:proxy_pass http://127.0.0.1:8080;(无 URI 部分)会原样转发 /ws/ 路径,如果后端只认根路径不认 /ws/ 前缀,路径不对也可能被后端拒绝,核对一下后端实际监听的路径。5. 确认 Upgrade 头有没有被改写或丢掉的办法只看 Nginx error_log 不够,建议三处对照:(1)curl 复现握手,看状态码是不是 101:curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" http://你的域名/ws/(2)在 Nginx 日志格式里加上 $http_upgrade、$http_connection、$upstream_status、$upstream_addr,复现一次就知道 Nginx 收到和转发的头分别是什么。(3)后端侧对照:看后端接入日志收到的 Upgrade、Connection、Host;还可以在本机抓包 tcpdump -i lo -A port 8080,看实际到达后端的请求头有没有被改写。建议的动手顺序:先 nginx -T 确认生效配置并 reload;再 curl 复现并区分 400/502;先补 Host 三行头,再放开两个超时;最后用日志加抓包确认后端收到的头与浏览器发出的头一致。改完每次先 nginx -t 再 reload,确认无报错再复测。