query string 是什么?为什么在 rewrite 中容易出问题?
query string 就是 URL 中 ? 后面的部分,比如 /search?q=nginx&page=1 里的 q=nginx&page=1。它在网站运行中承担着传递参数、跟踪来源、分页浏览等关键功能。
但很多站长在配置 Nginx rewrite 规则时,经常遇到一个诡异问题:重定向之后,URL 里的参数全没了。用户搜的东西没了,分页状态没了,追踪参数也没了。这不是 Nginx 的 bug,而是没有搞清楚 rewrite 对 query string 的默认处理机制。
Nginx rewrite 对 query string 的默认处理规则
核心规则只有一句话:如果重写后的 URL 中不包含 ?,Nginx 会自动把原始请求的 query string 附加到新 URL 后面;如果重写的 URL 中包含了 ?,原始 query string 则不会自动附加。
看两个对比示例:
# 情况1:替换字符串中没有 ? # 原始请求 /old?q=test # 重写后变成 /new?q=test (原始参数被保留) rewrite ^/old$ /new last; # 情况2:替换字符串中有 ? # 原始请求 /old?q=test # 重写后变成 /new (原始参数被丢弃) rewrite ^/old$ /new? redirect;
这就是大多数人踩坑的地方:在 rewrite 的替换字符串里加了一个 ?(哪怕后面不接任何参数),原始 query string 就会被丢弃。
rewrite 指令末尾加/不加问号的区别
如果你希望在重写时主动保留原始 query string,有两种正确写法:
写法一:替换字符串不以 ? 结尾
# 原始参数会自动附加 rewrite ^/old$ /new last;
写法二:显式拼接 $is_args$args
# 无论替换字符串里有没有 ?,都手动把原始参数拼回去 rewrite ^/old$ /new$is_args$args last;
$is_args 是一个聪明的变量:当原始请求有 query string 时,它的值为 ?;没有时,它的值为空字符串。配合 $args(原始 query string 的值),就能精确控制参数传递。
保留原始 query string 的正确写法
实际配置中,最推荐的通用写法是:
location / {
rewrite ^/old-page$ /new-page$is_args$args last;
}
这样无论原始请求是否带参数,都能正确传递到重写后的 URL。
如果你需要追加自己的参数,同时保留原始参数:
# 注意这里的写法:?new_param=1&$args # 但更推荐用 $is_args$args 来避免重复 ? rewrite ^/old$ /new?source=rewrite&$args last;
注意:如果原始请求本身也有参数,上面这种写法会产生 /new?source=rewrite&q=test,是两个参数都保留,通常这是正确的行为。
实际案例:常见错误与修复
案例1:HTTP 跳转 HTTPS 后参数丢失
# 错误写法 return 301 https://$host$request_uri; # 实际上 $request_uri 已经包含了原始 query string # 所以这样写是对的!但很多人误以为要手动拼接,反而写错: # 真正容易出错的写法(多了一个 ? 导致重复) return 301 https://$host$uri?$args; # 如果原始URL是 /search?q=test,上面会变成 /search?q=test?q=test 这类异常
案例2:重写时丢失分页参数
# 错误:重定向后 page 参数没了 rewrite ^/category/([0-9]+)$ /archive.php?cat=$1? last; # 注意末尾多了一个 ? ,导致 $args 不会被附加 # 正确:去掉末尾的 ? rewrite ^/category/([0-9]+)$ /archive.php?cat=$1 last; # 或者显式拼接 rewrite ^/category/([0-9]+)$ /archive.php?cat=$1&$args last;
案例3:想要丢弃原始参数,只保留自己定义的参数
# 在替换字符串中加 ? ,原始参数就不会附加 rewrite ^/old$ /new?ref=home last; # 原始 ?utm_source=xxx 会被丢弃,只有 ref=home 生效
调试技巧:如何确认 query string 是否被正确传递
配置完 rewrite 规则后,用以下方法验证参数是否按预期传递:
方法1:用 curl 查看重定向目标
curl -I -L "http://your-site.com/old?q=test"
方法2:在 Nginx 配置里临时加 add_header 输出调试信息
add_header X-Debug-Args "$args"; add_header X-Debug-Request-URI "$request_uri";
方法3:查看 Nginx 访问日志中的 $args 和 $query_string
log_format debug '$uri | args=$args | query=$query_string'; access_log /var/log/nginx/debug.log debug;
这些方法可以帮你快速定位参数是在哪一步丢失的,而不用盲目猜测。
总结
Nginx rewrite 对 query string 的处理机制可以总结为三条铁律:
- 替换字符串不含
?→ 原始 query string 自动保留 - 替换字符串含
?→ 原始 query string 默认丢弃 - 想精确控制 → 用
$is_args$args显式拼接
记住这三条,rewrite 配置里的参数丢失问题基本可以杜绝。
相关文章:
Nginx rewrite重定向保留查询参数:5种场景+完整配置示例
Nginx rewrite保留查询参数完整教程
Nginx $request_uri和$uri区别详解:搞懂这两个变量,重定向再也不踩坑
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论