Nginx可通过$request_uri与$uri变量对比记录重写前后URL:$request_uri始终为原始URI(含参数),$uri为重写后路径(不含query string),配合set保存原始值及自定义log_format即可实现精准记录。

要在 Nginx 日志中记录 rewrite 重写前后的 URL,Nginx 本身不直接提供“重写前 URL”的变量,但可以通过合理利用内置变量和自定义变量(set 指令)来实现。关键思路是:在 rewrite 发生前保存原始请求 URI,再在日志格式中引用它。
1. 使用 $request_uri 与 $uri 区分原始与重写后路径
$request_uri 始终保留客户端发起的原始请求 URI(含参数,未解码),而 $uri 是经过 URI 解码、重写、内部跳转后的规范化路径(不含 query string)。这是最基础的对比依据:
-
$request_uri→ 重写前的完整请求(如/old/path?id=1) -
$uri→ 重写/内部处理后的路径(如/new/path),不含 query string -
$args或$query_string→ 查询参数部分(重写后可能被修改或保留)
2. 在 rewrite 前用 set 保存原始 URI(推荐方案)
因为 $request_uri 在整个请求生命周期中不变,通常已足够;但若需更精确控制(例如排除某些 rewrite 干扰),可在 location 开头显式保存:
location / {
# 在任何 rewrite 之前,保存原始 URI 到自定义变量
set $original_uri $request_uri;
<pre class="brush:php;toolbar:false;">rewrite ^/old/(.*)$ /new/$1? permanent;
rewrite ^/v1/(.*)$ /api/v2/$1 break;
# 其他配置...}
然后在 log_format 中使用 $original_uri —— 注意:该变量必须在 rewrite 之前定义,否则会被覆盖或为空。
3. 自定义日志格式并启用
在 http 或 server 块中定义日志格式,包含原始与当前路径信息:
log_format rewrite_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'orig:"$request_uri" → final:"$uri?$args"';然后在需要的 location 或 server 中启用:
access_log /var/log/nginx/rewrite.log rewrite_log;
示例日志输出:
192.168.1.100 - - [10/Jan/2025:14:22:33 +0800] "GET /old/page?id=123 HTTP/1.1" 301 169 "-" "curl/7.68.0" orig:"/old/page?id=123" → final:"/new/page?id=123"4. 验证 rewrite 是否生效及日志是否捕获正确
注意以下常见陷阱:
- 使用
rewrite ... last会触发新 location 匹配,$request_uri不变,但$uri已更新,日志仍可对比 - 使用
rewrite ... break不重新匹配 location,$uri改变但 location 不变,变量依然可用 - 避免在 if 块中使用 set + rewrite 组合(if 在 location 中行为复杂,易出错;优先用 rewrite 规则代替 if)
- 确保 log_format 定义在 access_log 引用之前,且语法无误(Nginx 启动时会校验)



















