Nginx rewrite捕获变量不跨指令持久保留,每次匹配重新赋值;last导致重匹配后$1失效,break则保留最后一次捕获;rewrite只操作$uri路径,不匹配$query_string。

在 Nginx 中,rewrite 规则里的捕获变量(如 $1、$2 或命名捕获 $name)**不会跨 rewrite 指令持久保留**,每次匹配成功后才会重新赋值;若多次 rewrite 连续触发,后一次匹配会覆盖前一次的捕获结果——这不是“变量污染”,而是设计如此。排查关键在于确认:哪次 rewrite 实际生效、捕获是否匹配成功、是否意外触发了后续 rewrite。
确认 rewrite 是否真正执行(而非仅匹配)
Nginx 的 rewrite 指令默认在 `server` 或 `location` 块中按顺序执行,但只有满足两个条件才会真正重写 URI 并影响后续处理:
- 正则表达式匹配成功(否则跳过该条 rewrite)
- 使用了
last、break、redirect或permanent标志(无标志时默认为last,即重写后重新匹配 location)
⚠️ 注意:last 会导致 URI 被重写后**立即终止当前 location,重新 search 匹配 location**,此时前一条 rewrite 的 $1 在新 location 中已不可用;而 break 则停止 rewrite 执行但不跳出 location,后续 rewrite 不再运行,捕获变量停留在最后一次匹配结果。
用 $args 和 log_format 定位实际捕获值
最直接的方式是把捕获内容记入 access 日志,验证每次 rewrite 前后的变量状态:
log_format debug '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$request_uri" "$uri" "$args" '
'cap1="$1" cap2="$2" named="$name" '
'host="$host"';
access_log /var/log/nginx/debug.log debug;
配合如下配置测试:
location /test/ {
rewrite ^/test/(\d+)/(.+) /api/v1/id/$1?name=$2 break;
rewrite ^/api/v1/id/(\d+)\?name=(.+) /final?id=$1&value=$2 break;
}
你会发现第二条 rewrite **根本不会执行**——因为 ?name=... 不在 $uri 中(query string 属于 $args),正则无法匹配。这是常见误判根源:rewrite 只操作 URI 路径部分($uri),不包含 query string。
避免“链式捕获覆盖”的安全写法
若需多步转换,推荐一次性完成,或用 map 提前提取,而非依赖连续 rewrite 的中间变量:
- ✅ 推荐:单条 rewrite 完成全部逻辑,例如
rewrite ^/old/(\d+)/(\w+) /new?id=$1&tag=$2? last; - ✅ 推荐:用
map提前解析并固化变量,再在 rewrite 中引用:map $uri $extracted_id { ~^/src/(\d+)/.* $1; }rewrite ^/src/ /dest?id=$extracted_id? last; - ❌ 避免:依赖
$1在多个 rewrite 间传递,尤其混用last和路径变更
检查 rewrite 执行顺序与 location 重匹配行为
使用 nginx -t -v 验证语法,并开启 debug 日志定位真实执行流:
error_log /var/log/nginx/error.log debug;
在 debug 日志中搜索 "rewrite" 关键字,你会看到类似:
*123456 test location: "/test/123/abc"
*123456 using configuration "/test/"
*123456 rewrite: "/test/123/abc" -> "/api/v1/id/123?name=abc"
*123456 rewritten redirect: "/api/v1/id/123?name=abc"
这说明 rewrite 已触发,且新 URI 带 query string ——但注意:这个 query string 是 rewrite 后附加的,**不会参与下一条 rewrite 的正则匹配**(除非你显式在正则里写 \?,而这通常无效,因 $uri 不含 ?)。


















