Nginx不支持直接按上游状态码路由,但可通过proxy_next_upstream实现自动重试、error_page+named location实现降级跳转、OpenResty+Lua实现精细状态码路由。

Nginx 本身不直接支持根据上游返回的 HTTP 状态码(如 500、404、429)动态切换后端分发目标,它没有内置的“按状态码路由”指令。但可以通过组合使用 proxy_next_upstream、error_page、map 和 upstream 的状态控制机制,间接实现基于响应状态码的请求重试、降级或分流逻辑。
下面介绍几种实用、生产环境验证过的实现方式:
基于 proxy_next_upstream 的自动重试与故障转移
该指令决定在什么情况下将请求转发给下一个 upstream server,适用于容错重试场景(不是“分发”,而是“兜底重试”):
upstream backend {
server 10.0.0.10:8080;
server 10.0.0.11:8080;
server 10.0.0.12:8080 backup;
}
server {
location /api/ {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 10s;
}
}- 当后端返回
500、502等指定状态码时,Nginx 会自动尝试下一个可用 server(含 backup) - 注意:这不会改变原始分发逻辑(如轮询顺序),只是失败后重试;且仅对当前请求生效,不改变后续请求的路由
使用 error_page + named location 实现状态码驱动的降级跳转
可将特定错误状态码捕获,并重定向到备用 upstream 或静态响应:
upstream primary { server 10.0.0.10:8080; }
upstream fallback { server 10.0.0.20:8080; }
upstream static_fallback { server 127.0.0.1:8081; } # 返回兜底页面
server {
location /service/ {
proxy_pass http://primary;
proxy_intercept_errors on; # 启用 error_page 拦截
# 捕获 500/502/503 并跳转到 fallback
error_page 500 502 503 = @fallback;
}
location @fallback {
proxy_pass http://fallback;
}
# 可再设一层兜底:fallback 也失败时返回本地页面
location /service/ {
proxy_pass http://fallback;
proxy_intercept_errors on;
error_page 500 502 503 = @static_fallback;
}
location @static_fallback {
proxy_pass http://static_fallback;
}
}-
proxy_intercept_errors on是关键,否则 error_page 不生效 -
= @name表示内部重定向(不改变 URL,不返回 302) - 适合灰度发布、主备切换、API 降级等场景
利用 map + $upstreamhttp* 提取响应头做条件判断(需配合 Lua 或 OpenResty)
纯 Nginx 配置无法读取上游响应体或状态码变量用于 map,但可通过 ngx_http_lua_module 实现真正意义上的“状态码路由”:
# 需启用 lua-resty-core 和 lua-nginx-module
location /smart/ {
access_by_lua_block {
local res = ngx.location.capture("/upstream_proxy")
if res.status == 503 then
ngx.exec("@maintenance")
elseif res.status == 429 then
ngx.exec("@rate_limited")
else
ngx.status = res.status
ngx.header.content_type = res.header["content-type"]
ngx.print(res.body)
end
}
}
location @maintenance {
return 503 '{"msg":"Service under maintenance"}';
}
location @rate_limited {
return 429 '{"msg":"Too many requests"}';
}
location /upstream_proxy {
internal;
proxy_pass http://primary;
proxy_hide_header X-Upstream;
}- 这属于高级用法,依赖 OpenResty,适合需要精细化控制的业务网关层
- 不推荐在高并发简单场景滥用,有性能开销
小结:实际选型建议
-
只想自动避开坏节点? → 用
proxy_next_upstream配合健康检查(最轻量) -
主服务异常时切到备用 API? →
error_page+proxy_intercept_errors(标准、稳定) - 需要根据 401 跳登录页、404 渲染 SPA、429 返回限流头? → OpenResty + Lua(灵活但复杂)
-
误以为
map $status可用? → ❌$status是 Nginx 自身响应状态,不是 upstream 返回值,不可用于 upstream 分发决策
Nginx 的设计哲学是“配置即策略”,状态码处理偏向容错与降级,而非动态路由引擎。真要实现复杂响应驱动的分发,建议前置一层 API 网关(如 Kong、APISIX)或升级至 OpenResty 生态。


















