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 是 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 conditionif ($arg_id != "" && $arg_type = "img") { ... }
map 指令在 http 块中定义,可基于多个变量生成新变量,适合“与/或”逻辑:
http {map "$arg_id:$arg_type" $should_rewrite {default0;"~^[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 或重写后重新解析。
对复杂跳转逻辑,比 if + rewrite 更可靠:
location / {# 先检查是否有特定参数,有则进命名 locationif ($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,能避开大部分坑。