0

Nginx return 301 双重问号问题解决:查询参数拼接的正确姿势

2026.05.29 | youres | 6次围观

在Nginx配置301重定向时,很多开发者遇到过URL出现双重问号的问题,比如原本应该是https://example.com/page?param=value,结果变成了https://example.com/page??param=value。这个问题不仅影响URL美观,更会导致查询参数无法正确传递,影响网站功能。

问题现象:双重问号从哪来的?

先看一个典型的错误配置:

# 错误写法:会导致双重问号
return 301 https://example.com$new_request_uri?$args;

当原始请求是http://example.com/page?utm_source=google时,上述配置会生成:

https://example.com/page?utm_source=google?utm_source=google

原因很简单:$request_uri已经包含了问号和查询参数,再加一个?$args就重复了。

根本原因:变量理解不透彻

要彻底解决这个问题,必须先搞清楚Nginx几个关键变量的含义:

变量含义示例值
$uri请求路径(不含问号和参数)/page
$args查询参数(不含问号)utm_source=google
$is_args如果有参数返回"?",否则为空?
$request_uri完整请求URI(含问号和参数)/page?utm_source=google

三种正确写法对比

方法一:使用$request_uri直接跳转

最简单的方式,直接用$request_uri保留完整请求:

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

优点:简洁,自动保留所有参数
缺点:无法过滤或修改特定参数

方法二:$uri配合$is_args$args拼接

这是最灵活的写法,可以控制参数传递:

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

原理$is_args会自动判断是否需要加问号

  • 有参数时:$uri$is_args$args = /page?utm_source=google
  • 无参数时:$uri$is_args$args = /page(不会出现多余问号)

方法三:rewrite指令自动处理

rewrite指令会自动保留原参数(除非替换字符串以问号结尾):

server {
    listen 80;
    server_name example.com;
    rewrite ^(.*)$ https://example.com$1 permanent;
}

常见错误场景与修复

场景一:想要追加新参数

错误写法:

# 错误:会导致双重问号
return 301 https://example.com$request_uri?newparam=value;

正确写法:

# 使用$uri$is_args$args拼接,再手动加新参数
set $new_uri "https://example.com$uri";
if ($args) {
    set $new_uri "$new_uri?$args&newparam=value";
}
if ($args = "") {
    set $new_uri "$new_uri?newparam=value";
}
return 301 $new_uri;

更简洁的方式(使用map指令):

map $args $new_args {
    default "${args}&newparam=value";
    ""      "newparam=value";
}

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

场景二:想要过滤特定参数

只保留utm参数,丢弃其他参数:

# 提取utm_source参数
if ($args ~* "utm_source=([^&]+)") {
    set $utm_source $1;
    return 301 https://example.com$uri?utm_source=$utm_source;
}
return 301 https://example.com$uri;

场景三:跨域名跳转保留参数

从旧域名跳转到新域名,同时保留所有参数:

server {
    listen 80;
    server_name old-domain.com;
    return 301 https://new-domain.com$request_uri;
}

验证方法:curl测试

使用curl的-L参数跟踪重定向,验证最终URL:

# 测试带参数的请求
curl -L -I "http://example.com/page?utm_source=google"

# 查看重定向链路
curl -L -v "http://example.com/page?utm_source=google" 2>&1 | grep "Location:"

正确的输出应该只有一个问号:

Location: https://example.com/page?utm_source=google

总结:避免双重问号的核心原则

  1. 理解变量$request_uri已含问号,不要再加?
  2. 使用$is_args:让Nginx自动判断是否需要问号
  3. rewrite自动处理:rewrite默认保留原参数
  4. 测试验证:用curl跟踪重定向链路确认结果

掌握这些原则,双重问号问题将不再困扰你。

相关文章

版权声明

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

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