一个老站迁移,重写规则写完后发现跳转地址变成了 /new?a=1&a=1,参数被拼了两遍。查了半天,问题出在 rewrite 里用了 $request_uri,而这个变量带着原始查询串。
两个变量的本质区别
$request_uri 是客户端发来的原始 URI,带查询参数,不做解码,/list?page=2 里连问号一起保留。$uri 是规范化之后的路径,做过解码、合并斜杠,且不含参数。要拿参数得另外用 $args 或 $query_string。
rewrite 里的典型错法
写成 rewrite ^ /new permanent; 时 nginx 会自动保留原参数,不用你手动拼。如果目标地址写成 /new?$request_uri,参数就会重复甚至路径也带进去。匹配条件里用 $request_uri 还有个坑:中文和空格是 %XX 形式,正则写中文匹配不上,得用 $uri。
日志里看哪个
默认 combined 格式里的 request 就是 $request_uri 加协议版本,排查时能还原用户到底请求了什么。想去掉参数统计路径,就把日志格式改成 $uri,两边对照着看很快能发现问题。
- 做路径判断用 $uri
- 要看原始请求、做签名校验用 $request_uri
- 取参数单独用 $args,别从 $request_uri 里截
proxy_pass 后面拼变量时尤其要小心,$request_uri 会把参数原样带过去,多数情况是想要的,但配上 rewrite 就容易翻倍,改完记得用 curl 带上参数验证一遍。