在Nginx中做重定向时,很多人对return和rewrite的行为感到困惑,尤其是参数是否保留这个问题。实际上,两者的表现完全不同——这直接决定了你该用哪个指令。
核心差异:return 不带参数,rewrite 可以控制
这是两者最本质的区别。
return指令在处理重定向时,不会自动携带查询参数。当你配置:
return 301 https://example.com/target;
访问 https://example.com/source?foo=bar 时,浏览器最终会跳转到 https://example.com/target,而 ?foo=bar 被完全丢弃。
而rewrite的行为则不同。默认情况下,rewrite会保留原始的查询参数:
rewrite ^/old-page /new-page permanent;
访问 /old-page?id=123 会跳转到 /new-page?id=123,参数自动跟随。但这里有个前提:你的目标路径里不能写死查询字符串。
为什么 return 默认丢失参数?
Nginx 的return指令是直接发送 HTTP 响应头中的 Location 字段。当你在return里指定了一个 URL,这个 URL 就作为 Location 的值,Nginx 不会自动附加原始请求的查询参数。
这是符合 HTTP 规范的——Location header 本身就是完整的目标地址。但实际业务中,保留参数往往是刚需。
return 如何手动保留参数?
如果一定要用return,又想保留参数,需要用变量拼接:
location /old {
return 301 https://example.com/new`$request_uri;
}
$request_uri 包含了原始 URI 和查询参数,这样拼接后参数就能保留。但要注意:$request_uri 是完整的路径,从/开始,如果你的目标是绝对 URL,路径部分要从头写起。
另一种写法:
return 301 https://example.com/new`$is_args`$args;
$is_args 在有参数时返回?,无参数时返回空;$args 就是查询参数字符串。这种方式更精确地控制参数部分。
rewrite 保留参数时的一个坑
很多人以为 rewrite 默认保留参数就万事大吉了,其实不然。如果你显式写了带?的目标路径,参数会被丢弃:
# 这会丢失原始参数
rewrite ^/old /new? permanent;
末尾的?告诉 Nginx 清空所有查询参数。所以如果要手动控制参数,写法上要注意。
两者性能对比
从性能角度,return比rewrite更高效——return是 Nginx 内部的直接响应,不需要经过正则匹配引擎。官方文档明确说return是 stop processing 级别的指令,执行完就结束。
但实际差异通常可以忽略不计,除非你的并发量极高。
实战场景选择建议
- 简单跳转,参数需要保留:用
rewrite,最省事。 - 跨域名跳转:用
return 301+$request_uri,语义更清晰。 - 参数需要过滤或修改:只能用
rewrite,因为 return 没法对参数做二次处理。 - 绝对性能和简单性优先:用
return。
最常见的错误场景
很多人在 HTTPS 强制跳转时这样写:
return 301 https://`$host`$request_uri;
这个配置本身是对的,能保留参数。但如果你写成了:
return 301 https://`$host/;
那所有参数就全丢了,这就是为什么很多人发现"重定向后表单数据丢了"的根本原因。
总结
Nginx 的return和rewrite在参数处理上的差异不是 bug,而是设计选择。return直接发送指定 URL,默认不带参数;rewrite在同 server 内默认保留参数,跨域名跳转时也取决于你的写法。
理解了这个本质,你就不会再踩坑了。
相关阅读:
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论