nginx rewrite 默认保留原始 query string,修改参数需显式拼接或用 set/map 构造新 $args;last 触发重新匹配,break 终止重写;删参需手动过滤或借助 map/lua。

在 Nginx 中,rewrite 指令可用于修改请求 URI,包括提取、替换或重写 URL 中的参数(query string),但需注意:rewrite 默认只操作 URI 路径部分,不自动处理 query string;若要改写参数,必须显式拼接或使用 set + rewrite 配合。
理解 rewrite 对参数的默认行为
Nginx 的 rewrite 默认保留原始 query string。例如:
访问 /old/a?x=1&y=2 会重写为 /new/a?x=1&y=2 —— 参数原样保留。
若想修改、删除或新增参数,需主动控制 query string,常见方式有:
- 在 rewrite 目标中显式写出新参数(如
/new/$1?uid=$arg_id&v=2) - 用
set提取/构造参数变量,再拼入 rewrite 目标 - 用
return或rewrite ... last/break配合$args或$query_string控制参数
替换某个参数值(例如将 ?id=123 → ?uid=123)
直接用 $arg_参数名 获取原始值,再在 rewrite 目标中重新组织:
{
rewrite ^/api/user$ /api/profile?uid=$arg_id last;
}
访问 /api/user?id=123 → 内部重写为 /api/profile?uid=123(原 id 参数被丢弃,新参数 uid 取代)。
注意:last 表示内部重定向,Nginx 会重新匹配 location;若只想改写路径不改变匹配逻辑,可用 break。
保留部分参数 + 替换/新增(例如保留 utm_source,替换 version)
无法直接“修改”参数,只能重建 query string。可结合 map 或 set 提取所需参数,再拼接:
if ($arg_version) { set $new_args "version=v2"; }
if ($arg_utm_source) {
set $new_args "$new_args$arg_utm_source";
if ($new_args != "") { set $new_args "$new_args&utm_source=$arg_utm_source"; }
else { set $new_args "utm_source=$arg_utm_source"; }
}
rewrite ^/v1/(.*)$ /v2/$1?$new_args? last;
更稳妥做法是用 map 预定义逻辑(推荐用于复杂场景):
default "";
"~*version=(\d+)" "version=v2";
"~*utm_source=([^&]+)" "utm_source=$1";
}
location /v1/
{
rewrite ^/v1/(.*)$ /v2/$1?$new_query? last;
}
$new_query? 结尾的 ? 表示丢弃原始参数,只用你构造的。
删除某个参数(如去掉 ?debug=1)
没有内置“删参”指令,需手动过滤。简单场景可用正则匹配排除:
rewrite ^(.*)\?((?!debug=).*)$ $1?$2? break;rewrite ^(.*)\?debug=[^&]*(?:&|$)(.*)$ $1?$2? break;
rewrite ^(.*)\?$ $1? break;
但正则删参易出错,生产环境建议用 perl_set 或 Lua(OpenResty),或交由后端处理。更实用的方式是:用 if 判断并 set 空值,再统一拼接关键参数。
例如只保留 id 和 lang,忽略其余:
if ($arg_id) { set $safe_args "id=$arg_id"; }
if ($arg_lang) {
if ($safe_args != "") { set $safe_args "$safe_args&lang=$arg_lang"; }
else { set $safe_args "lang=$arg_lang"; }
}
rewrite ^/(.*)$ /clean/$1?$safe_args? break;
rewrite 处理参数本质是字符串重组,核心在于控制 $args 的生成方式。避免过度依赖嵌套 if,优先用 map 或应用层处理更清晰可靠。











