目录
- 问题现象:跳转后问号没了
- 根本原因:return和rewrite对参数的处理机制不同
- 方法一:return 301配合$request_uri(推荐)
- 方法二:rewrite拼接$is_args$args
- 方法三:if判断内使用$args变量
- 方法四:proxy_redirect处理反向代理场景
- 常见错误避坑
- 总结对比表
问题现象:跳转后问号没了
配置HTTP强制跳转HTTPS后,访问 http://example.com/search?q=nginx,跳转到了 https://example.com/search,查询参数 ?q=nginx 不见了。
这在涉及搜索页、追踪参数、分页参数等场景下影响严重——用户搜索结果丢失、推广统计断裂、分页失效。
根本原因:return和rewrite对参数的处理机制不同
这是Nginx参数丢失的核心原理:
- return 301/302 加完整URL:只返回你写的那个地址,不会自动附加原始查询参数
- return 301/302 加$request_uri:$request_uri 包含完整的路径和查询参数,所以参数不会丢
- rewrite 不带问号:Nginx会自动把原始查询参数附加到重写后的URL后面
- rewrite 带问号:问号后面的内容会替换原始查询参数,如果问号后面为空则清空参数
搞懂这4条规则,参数丢失问题迎刃而解。
方法一:return 301配合$request_uri(推荐)
这是最简单、最不容易出错的方式:
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
为什么有效:$request_uri 变量存储的是客户端请求的完整URI,包含路径和查询字符串。比如访问 /search?q=nginx&page=2,$request_uri 的值就是 /search?q=nginx&page=2,跳转后参数完整保留。
注意:不要写成 return 301 https://$host$uri,因为 $uri 不含查询参数,参数会丢失。
方法二:rewrite拼接$is_args$args
当你需要更灵活的重写规则时,用rewrite配合 $is_args 和 $args:
server {
listen 80;
server_name example.com;
rewrite ^(.*)$ https://$host$1$is_args$args permanent;
}
变量解释:
$is_args:如果请求有查询参数,值为?,否则为空字符串$args:查询参数的值部分(不含问号),如q=nginx&page=2
拼接起来就是 ?$args 或者空字符串,自动适配有无参数两种情况。
为什么不直接用rewrite不带问号:因为rewrite不带问号时Nginx会自动附加原始参数,效果一样。但显式写 $is_args$args 更清晰,也方便你在中间做参数过滤或替换。
方法三:if判断内使用$args变量
有些场景需要在特定条件下跳转,比如只对某个路径跳转:
server {
listen 80;
server_name example.com;
location /api/ {
if ($scheme = http) {
return 301 https://$host$request_uri;
}
}
}
这里同样使用 $request_uri 保证参数完整。如果一定要在if内用rewrite:
if ($scheme = http) {
rewrite ^(.*)$ https://$host$1$is_args$args permanent;
}
提示:Nginx官方建议尽量避免if指令("If Is Evil"),能用location+return的方式就别用if。
方法四:proxy_redirect处理反向代理场景
如果Nginx作为反向代理,后端返回302重定向时Location头可能是HTTP地址且缺少参数,这时候需要 proxy_redirect 来修正:
server {
listen 443 ssl;
server_name example.com;
location / {
proxy_pass http://backend:8080;
proxy_redirect http://example.com/ https://example.com/;
}
}
proxy_redirect 会将后端返回的 http://example.com/path?q=xxx 替换为 https://example.com/path?q=xxx,参数不会丢失。
常见错误避坑
错误1:return 301加了路径再手动拼参数
# ❌ 错误写法
return 301 https://$host/xxx?$args;
当 $args 为空时,URL末尾会多出一个 ?,虽然不影响功能但不美观。而且如果原始请求没参数,$is_args$args 能自动省略问号,直接写 ?$args 做不到。
错误2:rewrite带空问号清空了参数
# ❌ 参数被清空
rewrite ^(.*)$ https://$host$1? permanent;
rewrite中 ? 后面如果为空,Nginx会认为你要清空查询参数。这是rewrite的语法特性:不带问号则自动保留原始参数,带问号则用问号后面的内容替换。
错误3:混淆$uri和$request_uri
$uri 是经过Nginx处理后的路径(不含参数、可能被rewrite修改过),$request_uri 是原始请求的完整URI(含参数、不会被rewrite修改)。做重定向时优先用 $request_uri。
总结对比表
| 方法 | 配置方式 | 参数保留 | 适用场景 |
|---|---|---|---|
| return + $request_uri | return 301 https://$host$request_uri | ✅ 完整保留 | 全站跳转(首选) |
| rewrite + $is_args$args | rewrite ^(.*)$ https://$host$1$is_args$args permanent | ✅ 完整保留 | 需要灵活重写 |
| rewrite不带问号 | rewrite ^(.*)$ https://$host$1 permanent | ✅ 自动附加 | 简单跳转 |
| proxy_redirect | proxy_redirect http:// https:// | ✅ 完整保留 | 反向代理场景 |
| return + $uri | return 301 https://$host$uri | ❌ 参数丢失 | 不要用 |
| rewrite + 空问号 | rewrite ^ https://$host$1? permanent | ❌ 参数清空 | 不要用 |
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论