为什么要搞清楚 $is_args 和 $args 的组合
做Nginx重定向的时候,查询参数丢失是最常见的坑之一。很多人知道用 $request_uri 能保留完整路径,但有些场景你只需要保留参数部分,或者要对参数做过滤、拼接、修改——这时候就得靠 $is_args 和 $args 组合出击了。
这篇文章把这两个变量怎么搭配用、什么场景用、容易踩什么坑,一次讲清楚。
$is_args 和 $args 分别是什么
$is_args:问号本身
$is_args 的值只有两种可能:
- 请求URL中有查询参数时,值为
? - 请求URL中没有查询参数时,值为空字符串
""
举个例子:
# 请求:https://example.com/page?keyword=nginx
$is_args = "?"
# 请求:https://example.com/page
$is_args = ""
$args:问号后面的内容
$args 存的是查询字符串的完整内容,不包含问号:
# 请求:https://example.com/page?keyword=nginx&page=2
$args = "keyword=nginx&page=2"
# 请求:https://example.com/page
$args = ""
组合使用的核心逻辑
两个变量组合起来,就能在重定向时安全地拼接查询参数:
# 拼接公式
$uri$is_args$args
# 有参数时:/page?keyword=nginx&page=2
# 无参数时:/page
关键点在于 $is_args 自动处理了"有没有问号"这个问题——有参数它就补问号,没参数它就不补,不会出现 /page? 这种末尾拖个问号的情况。
5个实战场景
场景1:HTTP跳转HTTPS保留查询参数
最经典的应用,把HTTP请求301跳转到HTTPS,同时保留所有查询参数:
server {
listen 80;
server_name example.com;
# 方法1:用 $request_uri(最简单)
return 301 https://$host$request_uri;
# 方法2:用 $uri$is_args$args(更灵活)
return 301 https://$host$uri$is_args$args;
}
两种方法效果一样,但方法2更灵活——比如你只想保留特定参数时,方法1就做不到了。
场景2:重定向时追加新参数
跳转的同时需要加一个新参数(比如UTM追踪标记):
# 请求:/old-page?keyword=nginx
# 目标:/new-page?keyword=nginx&ref=migration
location /old-page {
if ($args) {
return 301 /new-page?${args}&ref=migration;
}
return 301 /new-page?ref=migration;
}
注意这里的判断逻辑:原来有参数,就用 & 连接新参数;原来没参数,新参数直接用 ? 开头。
场景3:重定向时过滤掉指定参数
跳转后想去掉某些参数(比如内部调试参数 debug),保留其他参数:
# 用 map 过滤参数
map $args $filtered_args {
~^(.*?)(?:&|^)debug=[^&]*(?:&(.*))?$ $1$2;
default $args;
}
server {
# 跳转时用过滤后的参数
location /old {
return 301 /new$uri$is_args$filtered_args;
}
}
这种参数过滤用 $request_uri 是做不了的,必须拆开来处理。
场景4:跨域名重定向保留参数
从一个域名跳到另一个域名,带上原始查询参数:
server {
listen 80;
server_name old-domain.com;
return 301 https://new-domain.com$uri$is_args$args;
}
这样 old-domain.com/search?q=nginx 就会跳转到 new-domain.com/search?q=nginx,参数完整保留。
场景5:日志中记录完整请求路径
自定义日志格式,把完整路径(含参数)记下来:
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'uri=$uri$is_args$args';
access_log /var/log/nginx/detailed.log detailed;
这样日志里就能看到每个请求的完整路径和参数,排查问题特别方便。
常见坑和避坑指南
坑1:末尾多出问号
如果你不用 $is_args,直接写 ?$args:
# 错误写法
return 301 https://$host$uri?$args;
# 请求 /page(无参数)时,跳转到 /page?,末尾多了个问号
虽然功能上不影响,但对SEO不友好,搜索引擎可能把 /page? 和 /page 当成两个不同的URL。用 $uri$is_args$args 就不会出现这个问题。
坑2:rewrite中问号的特殊含义
在 rewrite 指令中,替换字符串里的 ? 会导致原来的参数被丢弃:
# 这条rewrite会把原始参数全部丢弃
rewrite ^/old(.*)$ /new$1?redirected=true permanent;
# 正确做法:用 $is_args$args 保留原始参数
rewrite ^/old(.*)$ /new$1$is_args$args&redirected=true permanent;
这是 Nginx rewrite 的设计:替换字符串中出现 ? 就表示"用新的查询字符串替换旧的"。
坑3:$args 在 rewrite 后会变
$args 的值在 rewrite 执行后不会改变——它始终是原始请求的查询字符串。如果你在 rewrite 中修改了参数,新的参数会出现在 $query_string 里,但 $args 不受影响。
# $args 始终是原始的查询字符串
# $query_string 在 rewrite 后可能不同
# 实际上 $args 和 $query_string 是同一个东西,都不会因 rewrite 改变
纠正一下:$args 和 $query_string 其实是同一个变量的两个名字,值完全一样。如果你在 rewrite 的替换部分用 ? 设了新参数,新参数不会自动出现在 $args 里——它们会出现在最终的重定向URL中,但 $args 变量还是原始值。
$is_args$args 和 $request_uri 的选择
| 场景 | 推荐用 | 原因 |
|---|---|---|
| 简单跳转保留全部参数 | $request_uri | 代码最简洁 |
| 需要修改/追加参数 | $is_args$args | 可以灵活操作参数部分 |
| 需要过滤掉某些参数 | $is_args$args | $request_uri 无法拆分参数 |
| 只需要路径不需要参数 | $uri | $uri 不含查询字符串 |
| 日志记录 | $uri$is_args$args | 可读性好,字段拆分清晰 |
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论