nginx无法直接按后端状态码路由,但可通过proxy_next_upstream(如http_500/http_502)触发重试,并结合max_fails/fail_timeout实现被动健康检查,或借助health_check/lua实现主动探活。

在 Nginx 中,不能直接根据后端返回的 HTTP 状态码(比如 500、502、503)自动把请求转发到另一个上游服务器——Nginx 的 upstream 模块本身不解析响应体或状态码做路由决策。但可以通过组合使用 proxy_next_upstream、proxy_next_upstream_tries 和健康检查机制,实现“状态码触发的故障切换”效果。
利用 proxy_next_upstream 触发重试
这是最常用且有效的做法:当 Nginx 代理请求后,若收到特定错误状态码,就自动尝试下一个 upstream server。
-
关键配置项:
proxy_next_upstream error timeout http_500 http_502 http_503 http_504; - 其中
http_500等表示:只要后端返回这些状态码,Nginx 就认为本次请求失败,立即重试(前提是还有可用 server) - 必须配合
proxy_next_upstream_tries(默认 0,即无限重试)和proxy_next_upstream_timeout控制重试行为 - 注意:该机制只对当前请求生效,不改变 upstream 的“健康状态”,下次请求仍可能打到同一台出错的机器上
搭配被动健康检查提升稳定性
单靠重试不够,需让 Nginx 主动“标记”异常节点,避免持续轮询失败服务。
- 在
upstream块中启用max_fails和fail_timeout: server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;- 结合
proxy_next_upstream,每次失败(包括 5xx)都会计入失败次数;达到阈值后,该 server 在fail_timeout内被暂时剔除 - 这样既实现了“状态码触发重试”,又实现了“状态码累积触发临时下线”
主动健康检查(推荐用于关键服务)
如果需要更及时、更可控的故障发现,建议开启 health_check(需 Nginx Plus,或开源版配合第三方模块如 nginx_upstream_check_module)。
- 主动探针可定期 GET 一个健康接口(如
/health),依据返回状态码(如非 200)直接标记 server 不可用 - 相比被动检查,主动方式能提前拦截流量,避免用户感知到 5xx
- 开源版可通过 Lua 脚本(如
ngx_http_lua_module)+ 定时任务模拟,但复杂度较高,生产环境建议评估 Nginx Plus 或 OpenResty
注意事项与常见误区
实际配置中容易忽略的关键点:
- 确保
proxy_next_upstream中明确列出要重试的状态码;默认不包含任何 HTTP 状态码,仅响应超时和连接错误 -
proxy_intercept_errors on;会影响重试逻辑——若开启,Nginx 可能截获 5xx 并返回自定义错误页,导致无法触发proxy_next_upstream - 重试会增加延迟,对幂等性差的请求(如 POST)要谨慎;必要时可在应用层设计重试友好接口
- 日志中可通过
$upstream_addr和$upstream_status字段确认是否发生了重试及最终状态码











