0

Nginx rewrite query string处理机制详解:为什么参数总是丢失?

2026.05.26 | youres | 11次围观

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 的处理机制可以总结为三条铁律:

  1. 替换字符串不含 ? → 原始 query string 自动保留
  2. 替换字符串? → 原始 query string 默认丢弃
  3. 想精确控制 → 用 $is_args$args 显式拼接

记住这三条,rewrite 配置里的参数丢失问题基本可以杜绝。


相关文章:
Nginx rewrite重定向保留查询参数:5种场景+完整配置示例
Nginx rewrite保留查询参数完整教程
Nginx $request_uri和$uri区别详解:搞懂这两个变量,重定向再也不踩坑

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论