nginx中问号不是uri路径部分,location和rewrite只匹配$uri(不含?及参数);需用$args或$query_string变量结合if或map实现基于查询参数的重写,支持丢弃、保留或修改参数。

在 Nginx 中,问号(?)本身不是 URI 路径的一部分,而是分隔请求路径与查询参数(query string)的符号。Nginx 的 location 和 rewrite 指令默认只匹配 URI 的路径部分(即 $uri),不包含 ? 及其后的参数。因此,“带问号的 URL 规则重写”实际是指:根据原始请求中的查询参数(如 ?id=123&type=abc)做条件判断,并重写路径、修改或丢弃参数。
理解 $args 和 $query_string
Nginx 提供两个变量用于访问查询参数:
-
$args:原始未解码的查询字符串(例如
id=123&type=abc),可读可写;修改它会直接影响后续传递的参数。 -
$query_string:等同于
$args,只读别名,不能赋值。
注意:rewrite 指令本身不解析参数,也不支持直接在正则中匹配 ? —— 因为它根本不会出现在 $uri 中。
用 if + $args 实现参数条件重写
最常用的方式是结合 if 判断 $args,再用 rewrite 或 set 控制行为。例如,将含 redirect=1 的请求重写到新路径并清除参数:
location /old/ {
if ($args ~ redirect=1) {
rewrite ^/old/(.*)$ /new/$1? last;
}
}
说明:
-
~表示区分大小写的正则匹配;redirect=1匹配参数子串(不要求完整或开头); -
rewrite ... ?结尾的?表示丢弃原始参数; -
last表示内部重定向,继续匹配新 URI 的 location。
更安全的做法:用 map 预定义重写逻辑
避免在 location 中大量使用 if(有已知限制和陷阱),推荐用 map 提前提取参数值,再在 location 中使用:
map $args $new_path {
default "";
~*id=(\d+) "/article/$1";
~*cat=([^&]+) "/category/$1";
}
server {
location / {
if ($new_path) {
rewrite ^ $new_path? last;
}
}
}
说明:
-
map在 server 全局块中定义,支持正则捕获组($1); -
~*表示不区分大小写匹配; - 匹配成功时设置
$new_path,后续用if触发重写; - 结尾的
?确保不带原参数转发。
保留、修改或添加参数的技巧
若需保留部分参数、过滤或追加新参数,可用 set 拼接:
set $new_args "src=nginx";
if ($args ~ "id=(\d+)") {
set $new_args "$new_args&id=$1";
}
if ($args ~ "lang=([a-z]{2})") {
set $new_args "$new_args&lang=$1";
}
rewrite ^/page\.html$ /page.php?$new_args last;
注意:
- 拼接时用
&(HTML 实体),Nginx 内部会自动处理为 &; - 确保
$new_args有初始值,避免空参导致双问号; - 这种写法适合简单场景,复杂逻辑建议用 Lua(via lua-nginx-module)或后端处理。











