在 nginx 中,`rewrite` 指令默认不会自动拼接原始请求中的查询参数(即问号后的内容),这会导致参数丢失。要实现将带问号的参数拼接到新路径,必须在 `rewrite` 规则末尾显式添加 `?` 符号。这个问号的作用是告诉 nginx 丢弃原有的查询字符串,并保留当前 url 中通过正则捕获或硬编码的查询部分;如果希望保留原始参数,则需配合 `$is_args` 和 `$args` 变量手动拼接。

如何在新路径后保留原始查询参数
要保留原始查询参数,应使用 `$is_args` 和 `$args` 变量构建重写目标。`$is_args` 在存在参数时返回 `?`,否则为空;`$args` 包含完整的参数字符串。将它们追加到重写路径后即可实现无缝拼接。

server {
listen 80;
server_name example.com;
# 示例:将 /old/path 重定向到 /new/path,并保留原始参数
location /old/ {
rewrite ^/old/(.*)$ /new/$1$is_args$args last;
}
}
上述配置中,当访问 `/old/foo?bar=1` 时,Nginx 会匹配正则 `^/old/(.*)$`,捕获组 `$1` 为 `foo`。重写目标变为 `/new/foo`,随后附加 `$is_args`(值为 `?`)和 `$args`(值为 `bar=1`),最终结果为 `/new/foo?bar=1`。若原始请求无参数,如 `/old/foo`,则 `$is_args` 为空,结果仅为 `/new/foo`,不会产生多余的问号。
如何强制丢弃原有参数并添加新参数
若需清除原始参数并注入新参数,应在 `rewrite` 目标中直接写明新参数,且不引用 `$args`。此时若仍想保留某些特定参数,需手动提取;若完全丢弃,只需忽略 `$args` 即可。

server {
listen 80;
server_name example.com;
# 示例:重定向并丢弃原参数,添加固定参数
location /api/ {
rewrite ^/api/(.*)$ /v2/$1?version=2&format=json last;
}
}
在此配置中,访问 `/api/data?key=value` 会被重写为 `/v2/data?version=2&format=json`。注意,重写目标中直接写死了新参数,因此原始参数 `key=value` 被丢弃。若希望同时保留原始参数和新参数,可改为 `/v2/$1$is_args$args&version=2&format=json`,但需注意参数顺序和冲突处理。Nginx 不会自动去重,重复键可能导致不可预期行为。
当原始路径包含多个问号时会发生什么
Nginx 的 URL 解析遵循 RFC 3986,第一个 `?` 被视为查询字符串的开始,后续 `?` 视为普通字符。因此,若原始 URI 中包含多个 `?`,只有第一个之后的内容属于 `$args`。在 `rewrite` 中使用 `$args` 时,它会完整保留从第一个 `?` 开始的所有内容,包括后续的 `?` 字符。这意味着即使原始 URL 格式异常,只要它被 Nginx 接受,`$args` 就能正确捕获并传递全部参数部分。例如,访问 `/path?a=1?b=2`,`$args` 的值为 `a=1?b=2`,重写后可完整保留该结构。但需注意,大多数客户端和中间件可能无法正确处理含多个 `?` 的 URL,建议在前端或网关层进行规范化。











