Nginx rewrite默认不保留查询参数,必须显式拼接$args或使用$is_args$args;正则无法直接匹配问号后内容,需用if判断$args;$args只读,修改参数须通过set构造新变量。

Nginx 的 rewrite 指令默认不保留原始查询参数,除非显式在 replacement 中拼接或引用 $args。这是实际配置中最容易出错的地方——看似重写了路径,结果却意外丢失了 ?id=123&sort=desc 这类关键参数。
rewrite 默认会丢弃查询参数
当使用形如
rewrite ^/old$ /new last;
这种写法时,无论原始请求是 /old?a=1&b=2 还是 /old?x=y,重写后都只会变成 /new,所有查询参数被清空。
Nginx 不会自动继承 $args,它只处理 URI 路径部分(即 ? 之前的内容)。
要保留参数,必须手动带上 $args 变量:
rewrite ^/old$ /new?$args last;
或者更安全地用问号拼接(避免末尾多 ?):
rewrite ^/old$ /new$is_args$args last;
其中 $is_args 会在有参数时输出 ?,无参数时为空字符串,可防冗余问号。
重写时修改或过滤查询参数
常见需求不是“全保留”,而是“改一部分”或“去某几个”。
-
添加参数:
rewrite ^/product$ /product?id=100&source=nginx last;
-
替换某个参数值(需配合正则捕获):
rewrite ^/item\?id=(\d+)&type=(\w+)$ /item?id=$1&type=new_$2 last;
-
移除特定参数(例如去掉
debug=true):if ($args ~ "^((?!debug=).)*$") { set $clean_args $args; } if ($args ~ "^(.*)(?:&|^)debug=[^&]*(?:&|$)(.*)$") { set $clean_args "$1$2"; } rewrite ^/api/(.*)$ /api/$1?$clean_args last;⚠️ 注意:
if在 location 中慎用,且$args是只读变量,无法直接修改,只能通过set构造新变量。
location 与 rewrite 的执行顺序影响参数处理
Nginx 处理流程是:
→ 先匹配 location(仅基于路径,不看 ? 后内容)
→ 再执行该 location 内的 rewrite
→ 若 flag 为 last,会重新进入 location 匹配阶段(此时 $args 仍有效)
这意味着:
- 查询参数不影响
location匹配,但会影响rewrite中的正则匹配(如果正则里用了$args或if判断) -
rewrite中无法直接匹配?后的内容(因为 PCRE 默认不匹配 query string),必须用if ($args ...)配合字符串判断
实用建议
- 优先用
$is_args$args替代硬拼?$args,避免空参产生/? - 修改参数逻辑尽量放在
if+set组合中,而非复杂正则重写 - 避免在
location /块中大量if判断$args,性能损耗明显;高频场景建议用 Lua 或应用层处理 - 开启
rewrite_log on;(配合error_log notice;)可实时查看重写过程,验证参数是否按预期传递


















