前言
用Nginx做301永久重定向时,很多人会遇到这样的问题:配置写好了,浏览器跳转也正常,但跳转后的URL里查询参数全丢了。比如用户访问 https://old.com/page?id=123&from=baidu,跳转后变成了 https://new.com/page,后面的 ?id=123&from=baidu 凭空消失。
这个问题在SEO、流量追踪、登录态传递等场景下影响很大。本文就来讲清楚:Nginx的return指令为什么会丢参数,以及怎么配置才能把参数完整保留下来。
一、先搞懂为什么参数会丢失
看一个最常见的错误配置:
server {
listen 80;
server_name old.com;
return 301 https://new.com;
}
看起来已经用了 ,参数应该保留才对。但实际上,很多场景下这个配置依然会丢参数,原因是 本身包含了原始的查询字符串(/path?query=value),但如果Nginx在处理过程中经过了 proxy_pass 或者其他中间层,查询参数可能被过滤掉了。
更常见的问题是直接在 location 块里用了类似这样的写法:
location / {
return 301 https://new.com/;
}
这种写法只跳转到根路径 /,所有路径和参数全部丢失,跟没说一样。
二、3种实战配置:完整保留参数不丢失
方法1:用 保留完整原始URL
这是最直接的做法。 包含了原始请求的完整路径(含查询字符串)。
server {
listen 80;
server_name old.com www.old.com;
return 301 https://new.com;
}
效果:访问 http://old.com/article?id=5&ref=google → 跳转到 https://new.com/article?id=5&ref=google,参数原封不动。
适用场景:整站迁移、域名更换、HTTP强制跳转HTTPS。
方法2:用 手动拼接参数
是解码后的路径(不含查询参数), 在有参数时返回 ?, 是查询参数字符串。三者拼接即可还原完整URL:
server {
listen 80;
server_name old.com;
return 301 https://new.com;
}
效果同上,但写法更明确可控。在某些经过内部重写(rewrite)之后的场景,用 比 更可靠,因为它不受rewrite过程的影响。
适用场景:经过rewrite处理后的重定向、需要精确控制路径拼接的场景。
方法3:用map指令按需保留特定参数
有时候不需要保留全部参数,只想保留特定参数(如 utm_source),其余参数过滤掉避免干扰。可以结合 map 指令实现:
# 在http块中定义map
map {
~*^.*?(utm_source=[^&]+&?.*)$ ;
default "";
}
server {
listen 80;
server_name old.com;
set "https://new.com/";
if ( != "") {
set "https://new.com/?";
}
return 301 ;
}
这个写法相对复杂,但如果你做营销归因只想保留UTM参数,这种方式更干净。
适用场景:精准营销归因、只想保留特定参数的场景。
三、return 301 vs rewrite 在参数保留上的区别
很多同学会拿rewrite和return做对比。简单说:
- return:直接终止请求并返回响应(跳转),参数处理取决于你写的目标URL。
- rewrite:在server块内做路径重写,默认保留查询参数,但用
rewrite ... break或带?的写法时也会清空参数。
两者的参数行为其实是一致的关键在于你写目标URL时有没有显式包含参数部分。
四、实战场景:HTTP强制跳转HTTPS保留所有参数
这是最常见的使用场景。正确的写法:
server {
listen 80;
server_name _;
return 301 https://System.Management.Automation.Internal.Host.InternalHost;
}
server {
listen 443 ssl http2;
server_name _;
# SSL配置省略...
# 正常处理请求
}
注意这里用的是 System.Management.Automation.Internal.Host.InternalHost 而不是硬编码域名。System.Management.Automation.Internal.Host.InternalHost 会自动取当前访问的域名,更灵活,适合泛域名场景。
之前写过一篇 《Nginx rewrite重定向保留查询参数:5种场景+完整配置示例》,对rewrite和return的差异有更详细的对比,感兴趣的可以参考。
五、用curl验证参数是否完整保留
配置完后不要光靠浏览器看,浏览器会自动补全很多参数。用curl能看得更清楚:
# 直接查看301跳转后的Location头
curl -I -L http://old.com/page?id=123 2>/dev/null | grep -i location
# 对比两种写法的区别
curl -s -w "%{url_effective}\n" -o /dev/null "http://old.com/search?q=nginx&page=1"
如果Location头里包含了完整的查询参数,说明配置正确。
另外,Chrome浏览器可以用开发者工具 → Network → 点击那条301请求,查看Response Headers里的 Location 字段是否包含完整参数。
六、参数丢失的常见排查方向
如果配置了但参数还是丢了,从以下几个方向排查:
- 中间是否有CDN或负载均衡:Cloudflare、阿里云CDN等会在边缘层过滤参数,需要在CDN控制台单独配置"保留查询参数"。
- 是否经过了proxy_pass:Nginx作为反向代理时,proxy_pass本身不会丢参数,但配合return使用时要确保写在proxy_pass之前。
- :有同学会写成
/(多了一个斜杠),这样会把参数部分变成路径的一部分,导致参数丢失。 - 缓存问题:浏览器或CDN可能缓存了旧的301响应,清缓存后再测试。
总结
Nginx return 301 保留参数的核心就一句话:在目标URL里显式加上查询字符串。
三种方法的推荐顺序是:
- 优先用
return 301 https://new.com;——最简洁,适用于大多数场景。 - 需要精确控制时用
return 301 https://new.com;。 - 精准过滤参数时用map配合return。
记住这个原则,基本就不会再踩坑了。
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论