Nginx rewrite不支持直接写多条件逻辑,需用if配合map预计算变量实现安全判断;if仅支持单条件且不可嵌套,复杂逻辑应通过map生成布尔变量再用if触发rewrite。

Nginx 的 rewrite 规则本身不支持直接写复杂的条件判断(比如 if ($arg_x = "y") && ($http_user_agent ~* chrome) 这类组合逻辑),它依赖 if 指令配合 rewrite 使用,但要注意:if 在 location 块中行为受限,且嵌套、多条件组合容易出错。真正可靠的条件判断需结合 map、if 和 rewrite 分层设计。
用 if 指令做基础条件判断
if 是 Nginx 中唯一能写条件表达式的地方,语法简单但限制多:
- 只能出现在
server或location块内 - 不支持
&&/||运算符(不能写if (A && B)) - 条件成立时才执行其内部的
rewrite、set、return等指令
✅ 正确写法(单条件):
location /old/ {
if ($arg_type = "pdf") {
rewrite ^/old/(.*)$ /new/pdf/$1 permanent;
}
if ($http_referer ~* \.baidu\.com) {
rewrite ^/download/(.*)$ /cdn/$1 redirect;
}
}❌ 错误写法(多条件连写):
# Nginx 会直接报错:invalid condition
if ($arg_id != "" && $arg_type = "img") { ... }多个条件组合:用 map 预计算变量
map 指令在 http 块中定义,可基于多个变量生成新变量,适合“与/或”逻辑:
http {
map "$arg_id:$arg_type" $should_rewrite {
default 0;
"~^[0-9]+:img$" 1; # id 是数字 且 type=img
"~^:pdf$" 1; # id 为空(空字符串)且 type=pdf
}
server {
location /files/ {
if ($should_rewrite) {
rewrite ^/files/(.*)$ /static/$1 break;
}
}
}
}这样就把“$arg_id 非空 AND $arg_type == img”这种逻辑,转成一个预判变量 $should_rewrite,再用 if 判断,安全又清晰。
常见条件变量参考
这些变量可直接在 if 或 map 中使用:
-
$args:完整查询参数字符串(如a=1&b=2) -
$arg_xxx:单个参数值(如$arg_id→?id=123的值) -
$http_xxx:请求头(如$http_user_agent,$http_referer) -
$host,$request_uri,$scheme,$https -
$request_method:GET、POST等 - 正则匹配操作符:
=,!=,~(区分大小写)、~*(忽略大小写)、!~/!~*
⚠️ 注意:$args 修改后(如 rewrite ...?a=1 last)不会自动更新 $arg_a,要用 $query_string 或重写后重新解析。
替代方案:优先用 try_files + named location
对复杂跳转逻辑,比 if + rewrite 更可靠:
location / {
# 先检查是否有特定参数,有则进命名 location
if ($arg_v = "2") {
rewrite ^(.*)$ @v2 last;
}
try_files $uri $uri/ =404;
}
location @v2 {
rewrite ^/api/(.*)$ /v2/api/$1 break;
proxy_pass http://backend;
}或者更推荐完全避开 if,用 map + error_page + named location 实现条件分流,尤其在高并发场景下更稳定。
Nginx 的条件重写不是写代码,关键在“拆解逻辑 + 预判变量 + 少用 if”。把判断提前到 map,把动作收束到 location,能避开大部分坑。


















