Nginx rewrite本身不支持嵌套判断,需通过map预映射或多if+set变量组合实现;map最推荐,定义在http块中,按顺序首匹配即止,支持host、uri、参数等多特征组合映射;if仅允许单层判断,不可嵌套,且多个if独立执行、无短路逻辑。

Nginx 的 rewrite 指令本身不支持嵌套判断(比如 if 套 if),也不能在 rewrite 中直接写逻辑分支。所谓“嵌套判断”,实际要靠 if + set + rewrite 组合,或用 map 提前做条件映射来实现。核心原则是:**把多层逻辑拆成变量赋值和单层条件判断,避免在 rewrite 内部写条件**。
用 map 指令预定义多条件映射(推荐)
map 是最清晰、高效且安全的方式,适合处理多个请求特征组合判断(如 host + uri + 参数)。它在 server 或 http 块中定义,支持嵌套逻辑的等价表达:
map "$host:$request_uri" $redirect_target {
default "";
"example.com:/old/page" "/new/page";
"api.example.com:/v1/data" "/v2/data";
"~^test\.(.*):/beta/.*" "/stable$uri";
}
然后在 location 中直接使用:
location / {
if ($redirect_target) {
return 301 $redirect_target;
}
}
✅ 优点:无 if 嵌套风险,性能好,可读性强;❌ 注意:map 不支持正则捕获变量直接复用(如 $1),需用 ~ 开头并配合命名捕获(Nginx 1.11.2+ 支持 $name)。
用 if + set 拆解多层条件
如果必须用 if(例如需检查 $args 或 header),不要嵌套 if,而是用 set 逐步设置标记变量:
set $flag "";
if ($host = "www.example.com") {
set $flag "A";
}
if ($request_uri ~ "^/legacy/(.*)$") {
set $flag "${flag}B";
}
if ($flag = "AB") {
rewrite ^/legacy/(.*)$ /new/$1? permanent;
}
⚠️ 关键点:
- 每个 if 独立执行,不会短路;多个 if 同时满足时,$flag 会拼接(如 "AB")
- 不能在 if 中直接 rewrite 多次,否则行为不可控
- 避免对 $args 做复杂判断(如含多个参数),优先改用 map 或后端处理
避开 rewrite,用 return + 变量更可控
比起 rewrite,用 return 301/302 配合变量更简单安全,尤其适合跳转:
if ($host ~ "^(www\.)?old-site\.com$" ) {
set $target "https://new-site.com$request_uri";
}
if ($args ~ "ref=abc") {
set $target "${target}?ref=new";
}
if ($target) {
return 301 $target;
}
这样比 rewrite 更直观,也避免了 rewrite 的 URI 重写循环和末尾问号处理问题。
哪些情况根本不能“嵌套”?
以下写法是错误或无效的:
-
if (xxx) { if (yyy) { rewrite ... } }→ Nginx 语法不支持 if 嵌套 -
rewrite ^/a/(.*)$ /b/$1 break; if (...) { ... }→ rewrite 后的 break 会跳过后续 if,无法构成“嵌套逻辑” - 在 rewrite 正则中试图写条件(如
rewrite ^/(a|b)/?(?(1)foo|bar)$ ...)→ PCRE 条件子组在 Nginx 中不被支持
真正需要多条件路由时,优先考虑 upstream + proxy_pass 或交由应用层处理,Nginx 专注做轻量、确定性的转发决策。


















