nginx重写旧系统参数需区分uri路径匹配与$args参数处理,rewrite只匹配路径部分;常用类型包括仅改路径、多参数拼路径、参数转路径并保留部分参数;须注意last/break区别、防循环重写,推荐map替代if提升健壮性。

Nginx 重写旧系统参数(比如把带 query string 的动态 URL 改成更简洁、规范或兼容新系统的路径),关键在于区分 URI 路径匹配与参数处理逻辑,因为 rewrite 指令默认只匹配 $request_uri 的路径部分(不包含 ? 后的参数),而参数需用 $args 或 $arg_XXX 单独捕获或拼接。
下面从实际场景出发,讲清楚怎么配:
旧参数 URL 重写常见类型及配置方式
-
类型一:保留原参数,仅改路径
例如将/old.php?id=123&cat=tech→/article/123(忽略cat,只取id)location ~ ^/old\.php$ { if ($args ~* id=(\d+)) { set $id $1; rewrite ^/old\.php$ /article/$id? permanent; } }✅ 注意:
?在 replacement 末尾表示丢弃原始参数;不加?会自动追加原$args。 -
类型二:提取多个参数,拼成新路径
如/product.php?pid=100&color=red&size=l→/product/100/red/llocation ~ ^/product\.php$ { if ($args ~* pid=(\d+)&color=([^&]+)&size=([^&]+)) { set $pid $1; set $color $2; set $size $3; rewrite ^/product\.php$ /product/$pid/$color/$size? permanent; } }⚠️
if块内慎用,优先考虑map+rewrite组合(更健壮),但对简单参数提取,if可行。 -
类型三:参数转为路径,同时保留部分参数给后端
如/search.php?q=nginx&sort=date→/search/nginx?sort=datelocation ~ ^/search\.php$ { if ($args ~* q=([^&]+)) { set $q $1; rewrite ^/search\.php$ /search/$q?&$args break; } }?
$args是原始全部参数,&$args会补上sort=date等剩余参数;break防止后续 rewrite 干扰。
重写时必须注意的细节
rewrite不处理?后内容
正则^/old\.php$只匹配路径,不管?id=123。所以必须用$args或if ($args ~* ...)提取。-
last和break的区别很关键-
last:重写后重新匹配 location,适合内部跳转(如/article/123→location /article/) -
break:终止当前 rewrite 链,直接用新 URI 处理(常用于 proxy_pass 前整理路径)
-
避免循环重写
Nginx 最多执行 10 次 rewrite,超限返回 500。确保rewrite目标不再触发同一条规则(比如不要让/article/123又被location ~ \.php$捕获)。-
推荐用
map替代复杂if(更安全)map $args $new_path { ~*id=(\d+) "/article/$1"; ~*pid=(\d+)&.* "/product/$1"; default ""; } server { location ~ ^/(old|product)\.php$ { if ($new_path) { rewrite ^.*$ $new_path? permanent; } } }
实际调试建议
- 开启重写日志方便排查:
rewrite_log on; # 需配合 error_log notice error_log /var/log/nginx/error.log notice;
- 测试时用
curl -I看响应头,确认状态码(301/302)和Location是否正确 - 参数含特殊字符(如
/,+,%20)时,Nginx 默认已解码,正则中直接写明文(如q=nginx+test写成q=([^&]+)即可)
不复杂但容易忽略。











