WebSocket握手失败不能靠proxy_next_upstream自动重试解决,因其仅在收到502/504等可重试响应或网络异常时触发,而握手失败多因Nginx未透传Upgrade/Connection头导致后端根本未接收请求。

WebSocket 握手失败本身不能靠 proxy_next_upstream 自动重试解决。这个机制不适用于握手阶段的协议升级失败,原因在于:它只在请求已发往后端、且收到明确可重试响应(如 502/504)或网络异常(error/timeout)时才触发;而握手失败通常发生在 Nginx 未正确透传 Upgrade 头导致后端直接拒收,根本没走到“返回错误状态码”这一步。
先确保 WebSocket 握手能成功
proxy_next_upstream 是“兜底”,不是“修复”。必须先让首次握手稳定通过:
-
强制 HTTP/1.1:添加
proxy_http_version 1.1;,WebSocket 升级依赖此版本 -
透传关键头部:必须设置
proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade"; -
避免缓存干扰:禁用代理缓冲和压缩,加上
proxy_buffering off;proxy_http_version 1.1;proxy_set_header X-Accel-Buffering "no";
哪些情况 proxy_next_upstream 确实能起作用
它只对以下真实发生的、可重试的失败生效:
- 与某个 upstream 节点建立 TCP 连接失败(
error) - 发送 Upgrade 请求后等待响应超时(
timeout,需配合proxy_connect_timeout和proxy_send_timeout) - 后端返回 502/503/504 等网关类错误(需显式配置,如
http_502 http_503 http_504) - 后端返回非法响应头(
invalid_header),比如空行前有乱码
推荐的完整 WebSocket + 重试组合配置
放在对应 location 块中:
location /ws/ {
proxy_pass http://websocket_upstream;
<pre class="brush:php;toolbar:false;"># 必须项:协议升级支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# 关键超时:防止连接挂死或误判
proxy_connect_timeout 10s;
proxy_send_timeout 15s;
proxy_read_timeout 3600s; # 长连接保活,非握手阶段
# 可重试条件(仅对已发出请求后的失败有效)
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 20s;
# 禁用干扰项
proxy_buffering off;
proxy_http_version 1.1;
}
注意:proxy_next_upstream_timeout 是从第一次请求开始计时的总耗时上限,不是单次超时叠加。
真正可靠的高可用还需健康检查
proxy_next_upstream 每次仍可能先打到故障节点。要减少无效尝试,必须搭配主动健康检查:
- 在 upstream 块中启用
health_check(商业版)或使用check指令(开源版需 patch) - 或通过外部探针 + 动态配置更新,把已知宕机节点临时摘除
没有健康检查的 proxy_next_upstream,只是“撞运气式重试”,不是真正的高可用。











