Nginx 中 if + rewrite 仅适用于简单条件重写,须置于 server 或 location 块内,但存在执行时序、变量不更新、不支持嵌套等限制;推荐用 map + rewrite 实现安全高效的多条件映射。

Nginx 的 if 指令可以配合 rewrite 实现带条件的重写,但要注意它只能出现在 server 或 location 块中,且行为有局限性——if 在 location 内部是“伪指令”,不支持嵌套,也不推荐用于复杂逻辑。真正安全、高效的条件重写,优先用 map + rewrite 组合。
基础 if + rewrite 用法(简单场景可用)
if 判断的是变量值(如 $args、$host、$request_uri),满足条件时执行其内部的 rewrite 或其他指令(如 return、set)。注意:一个 if 块里只允许一个 rewrite,多次写会覆盖前一次。
- 判断 URL 参数含
test=1,重写到新路径:
# 注意:正则需转义 ?,$args 是原始参数串if ($args ~ test=1) {<br> rewrite ^/old\.html$ /new.html? break;<br> } - 判断 Host 不是 www.example.com,跳转到带 www 的 HTTPS:
if ($host != "www.example.com") {<br> return 301 https://www.example.com$request_uri;<br> }
if 的限制与常见坑点
这些行为容易引发意料外结果,务必避开:
- 不能在 if 中使用多个 rewrite 或混合 return:Nginx 会按顺序执行,但部分 rewrite 可能被跳过或重复触发
- $uri 和 $request_uri 在 if 中不更新:rewrite 后的路径不会反映在后续 if 判断中(因为 if 是“预检查”阶段)
- if 块内 set 变量无法用于外部 rewrite:作用域仅限当前块,且可能因执行时机导致为空
- 正则匹配慎用 $args:它不含 ?,且参数顺序不固定;更可靠的方式是用 $arg_XXX 直接取单个参数(如 $arg_test)
推荐替代方案:用 map 实现安全条件映射
map 在 server 级预定义变量映射关系,性能高、无执行时序问题,适合多条件分支。
- 示例:根据参数 test 值,映射不同目标路径:
map $arg_test $target_path {<br> default "/default.html";<br> "1" "/special.html";<br> "2" "/vip.html";<br> }<br> server {<br> location = /old.html {<br> rewrite ^(.*)$ $target_path? last;<br> }<br> } - 组合 host 和 uri 判断?可拼接字符串:
map "$host:$request_uri" $redirect_target {<br> "example.com:/admin" "https://manage.example.com";<br> "~*\.test\.com:/.*\.php$" "https://php-backend/";<br> }
实际调试建议
- 开启
error_log /path/to/log notice;,加rewrite_log on;(Nginx 1.19+ 改为debug_connection配合 debug 日志) - 用
curl -I http://domain/xxx验证响应头(尤其是 301/302 Location) - 避免在 if 中做耗时操作(如访问文件、DNS 查询),Nginx 是异步非阻塞,这类操作会卡住 worker
- 生产环境复杂规则,优先拆到应用层(如 PHP/Node)处理,Nginx 专注路由和静态分发


















