0

Nginx return 301 拼接问号和参数详细教程:3种正确写法让查询字符串不再丢失

2026.05.29 | youres | 4次围观

用 Nginx 的 return 指令做 301 重定向时,很多人会遇到查询参数丢失、URL 出现双重问号、或者参数莫名其妙被覆盖的问题。本文从原理出发,配合真实案例,讲清楚 return 301 后面怎么拼接问号和参数,以及哪些写法是错的。

一、return 301 默认行为:查询参数会丢失

先记住一个核心事实:Nginx 的 return 301 $url 默认情况下不会自动携带原请求的查询参数

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com/new-page;
}

访问 https://example.com/old-page?id=5&name=test,浏览器会被跳转到 https://example.com/new-page,后面什么都没有——?id=5&name=test 全部丢失。

这是因为 return 指令里的 URL 如果没有显式写查询字符串,Nginx 就不会附加任何参数。这和 rewrite 的默认行为不一样,rewrite 会在特定情况下自动追加原始参数。

二、三种正确的拼接写法

写法一:使用 $request_uri 自动携带全部参数(最常用)

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

$request_uri 包含完整的原始 URI(包含路径和查询字符串)。这种写法适合做全站 HTTP 到 HTTPS 的强制跳转,原始 URL 的所有信息都能完整传递到新地址。

适用场景:

  • 全站 HTTP 跳转到 HTTPS
  • 域名更换时的整站重定向
  • 需要保留所有原始查询参数的跳转

写法二:使用 $is_args 和 $args 手动拼接(更灵活)

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com/new-page$is_args$args;
}

解释一下这两个变量:

  • $is_args:如果有查询参数则返回 ?,没有则返回空字符串
  • $args:原始查询参数字符串(不含问号)

这样写的好处是:跳转目标 URL 是固定的,但同时能选择性保留原始参数。

举例:

  • 访问 /test?utm_source=baidu → 跳转到 /new-page?utm_source=baidu
  • 访问 /test(无参数) → 跳转到 /new-page(无问号)

$is_args 的自动判断避免了没有参数时 URL 末尾多出一个孤立问号的问题。

写法三:拼接固定参数 + 保留原始参数

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com/new-page?utm_campaign=redirect$is_args$args;
}

如果你想在跳转时追加自己的营销参数(比如 UTM 追踪码),同时保留原始参数,就这么写。实际 URL 会变成:

  • 访问 /page?ref=twitter → 跳转到 /new-page?utm_campaign=redirect&ref=twitter

不过这里有个坑需要注意:原始参数可能和你的固定参数发生键名冲突(比如都有 utm_source),需要用 map 指令做更精细的控制。

三、三种常见错误写法

错误一:写两个问号

# 错误写法
return 301 https://example.com/new-page?$request_uri;

很多人把 $request_uri 当作普通字符串拼进去,结果 URL 变成了:

https://example.com/new-page?/original-path?id=5

路径前面多了一个 /,而且问号出现两次,服务器根本读不对参数。这就是双重问号问题的根源。

如果需要用 $request_uri,直接拼在域名后面,不要再加 ?

# 正确
return 301 https://example.com$request_uri;

错误二:问号后面直接写 $request_uri

# 错误写法
return 301 https://example.com/new-page?$request_uri;

同错误一,$request_uri 包含完整路径和参数,再加问号就成了双重问号。

错误三:混用 $uri 和 $request_uri

# 有隐患的写法
return 301 https://example.com$uri?page=$arg_page;

这种写法逻辑复杂,不易维护。建议统一使用上述三种推荐写法之一。

四、完整配置示例

示例一:全站 HTTP 跳 HTTPS,保留所有参数

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    server_name example.com www.example.com;

    # 正常处理
    root /var/www/html;
    index index.html;
}

所有 HTTP 请求跳转到 HTTPS,并完整保留原始 URL 和查询参数。

示例二:特定页面跳转到新地址,追加 UTM 参数

location = /old-product {
    return 301 https://example.com/new-product?utm_source=website&medium=redirect$is_args$args;
}

适合产品页面迁移场景,既做了跳转追踪,又保留了原始搜索参数。

示例三:多参数场景下安全追加参数

map $args $filtered_args {
    default "$args";
}

server {
    listen 80;
    server_name example.com;
    return 301 https://example.com/new-page?utm_source=self$is_args$filtered_args;
}

这个写法先用 map 指令处理参数,再追加新的 UTM 参数,属于进阶用法。

五、用 curl 验证参数是否正确保留

写完配置后,用 curl 加上 -L 跟随重定向和 -I 只看响应头,检查跳转后的 URL 是否正确:

# 检查完整跳转链路和参数
curl -I -L "https://example.com/old-page?id=5&name=test"

# 加上 -w 查看最终 URL(Linux/macOS)
curl -L -w "Final URL: %{url_effective}" "https://example.com/old-page?id=5&name=test"

看输出里 Location: 响应头,确认参数格式是否正确(没有双重问号、没有多余问号)。

在 Linux/macOS 上直接用 curl,Windows PowerShell 里可以用 curl.exe 调用原生 curl,或者参考 PowerShell curl替代方案检查安全响应头

六、总结

核心要点就三句话:

  1. return 301 默认不携带查询参数,必须显式拼接
  2. $request_uri 自动带全部参数,或用 $is_args$args 灵活拼接
  3. 绝对不要在 $request_uri 前再加 ?,否则必出双重问号

掌握了这些,再配合 curl 验证,Nginx 重定向的参数问题基本不会再困扰你了。

相关推荐

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论
882文章数 0评论数
作者其它文章