Nginx WebSocket 反向代理排查:400、502、504 与超时
Nginx WebSocket 反向代理返回 400、502 或 504 时,按 Upgrade 握手、上游连接和超时日志逐项排查,并用 curl 与 websocat 验证配置。
Nginx WebSocket 反向代理返回 400、502 或 504 时,先记录响应状态并对照 Nginx 和上游日志。本文排查的是 Nginx 到上游的反向代理链路;400 优先检查请求或握手,502 检查上游连接与响应,504 检查上游响应时间和超时设置。状态码只能指示排查方向,根因要结合日志确认。
配好 Upgrade 和 Connection 转发头
先确认客户端是否发送 WebSocket 握手请求。Nginx 反向代理通常需要使用 HTTP/1.1,并将 Upgrade 与 Connection 头转给上游。配置结构如下,需放在正确的 http、server 或 location 层级,并按实际上游调整。
可对照 Nginx 官方 WebSocket 代理说明检查 Upgrade 转发行为;具体指令以部署版本文档为准。
```nginx
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
```
上例假设已在 http 层用 map $http_upgrade $connection_upgrade { default upgrade; '' close; } 定义 $connection_upgrade,并配置了对应 proxy_pass 和上游;按实际上游替换。5s 与 60s 只是示例值,需依据网络和心跳要求调整。proxy_connect_timeout 限制建立上游连接的等待时间;proxy_read_timeout 限制两次从上游读取数据之间的空闲间隔,不能修复连接拒绝或错误握手。
超时指令的版本和上下文限制见 Nginx 官方 proxy 模块文档。
随后查看客户端网络面板,确认失败发生在握手阶段还是握手之后。
看 400、502、504 判断请求卡在哪一环
| 状态码 | 优先检查 | 证据位置 | 后续动作 |
|---|---|---|---|
| 400 | 请求路径、Upgrade/Connection 头、上游对握手的校验 | 客户端请求、Nginx access log、上游响应 | 对照协议要求和上游路由,不盲目延长超时 |
| 502 | 上游地址/端口、连接拒绝、DNS 解析及上游进程状态 | Nginx error log、上游服务日志 | 先从 Nginx 主机验证到上游的连接 |
| 504 | 上游处理时间、连接/读取超时设置、服务负载 | error log 时间戳、上游耗时和负载 | 找出等待发生在哪一跳,再评估超时配置 |
用 access log 中的时间、URI、状态码及上游状态/耗时字段找到请求,再查看对应的 error log 和上游日志,确认请求是否到达上游、在哪一跳失败。不同版本和上游实现的返回状态可能不同,应沿同一请求的日志链路判断。
用客户端和两端日志复现并定位故障
记录 Nginx 版本、脱敏后的相关配置、目标路径、发生时间、响应状态、请求 ID 和上游日志。先验证客户端到 Nginx,再验证 Nginx 到上游;每次只调整一个配置项后复测。不要公开 token、Cookie、Authorization 头或内网敏感地址。
配置变更后先检查语法,再平滑重载,并分别验证普通 HTTP 与 WebSocket 握手。以下命令需在 Nginx 主机执行,域名和路径按环境替换:
```bash
sudo nginx -t
sudo nginx -s reload
curl -i https://example.com/ws
websocat -v wss://example.com/ws
```
nginx -t 失败时不要 reload。普通 curl 通常没有发送完整 Upgrade 握手,不能用它判定 WebSocket 成功;websocat 应完成握手并建立连接,成功响应为 101 Switching Protocols。结合 Nginx access/error log 中的 $upstream_status、$upstream_connect_time 和 $upstream_response_time 定位失败阶段。
根据日志区分握手失败、上游连接失败和响应超时
请求未到达上游时,检查 Nginx 配置、DNS 和连接;上游返回 400 时核对 Upgrade/Connection 请求头、路径和上游校验;上游连接被拒绝或出现 502 时检查地址、端口及服务状态;只有日志显示请求已到达上游且等待超过当前限制时,才按官方 proxy 模块文档评估超时。每次只改一个配置项,并用相同路径复测。
FAQ
proxy_read_timeout 调大后仍返回 504,下一步看什么?
按正文日志分支确认请求是否到达上游、等待发生在哪一跳,再检查上游耗时和服务负载;不要只通过继续增大超时处理上游不可用或链路异常。
curl 返回 200 就能证明 WebSocket 正常吗?
不能。普通 curl 请求不一定发送 WebSocket Upgrade 握手;应使用 WebSocket 客户端验证,并确认握手成功返回 101 Switching Protocols,再观察连接是否按预期维持。
对照日志复测 WebSocket 修复结果
按失败请求的时间戳复核 access/error log 与上游日志,再用相同路径确认握手是否返回 101、连接能否维持。若故障发生在客户端代理 IP 到 Nginx 之前,应另查客户端到代理的连接链路。
