问题现象
在 Nginx 配置中,为了让 HTTP 跳转 HTTPS 时保留查询参数(比如 UTM 追踪参数、分页参数 page 等),很多人会用 return 301 https://$host$request_uri; 这样的写法。配置看起来没问题,但跳转后浏览器却报 404,页面找不到。
这个问题在配置看起来"完全正确"的情况下尤其让人困惑。本文把最常见的 5 个原因逐一拆解,帮你快速定位并修复。
原因一:return 301 后面跟的 URL 路径和实际站点目录不匹配
这是最常见的原因。来看一个典型错误配置:
server {
listen 80;
server_name www.example.com;
return 301 https://www.example.com$request_uri;
}
看起来没问题,但如果你的 HTTPS server 块里 root 路径配置错误,或者 location / 里的 root 指向了错误的目录,跳转后 Nginx 找不到对应的文件,就会返回 404。
排查方法:直接在浏览器访问 HTTPS 地址(不带参数),看是否 404。如果直接访问也 404,说明问题在 HTTPS server 块的 root 或 index 配置,和参数保留无关。
原因二:$request_uri 包含了错误的路径前缀
$request_uri 包含完整的原始请求 URI(含查询参数),但如果你在配置里手动拼接了路径,可能会重复或缺失。
错误示例:
# 错误:手动加了 / 前缀,和 $request_uri 里的 / 重复
return 301 https://$host/$request_uri;
$request_uri 本身就以 / 开头,上面这样写会变成 https://example.com//path?param=1,双斜杠在某些情况下会导致 Nginx 匹配不到 location,返回 404。
正确写法:
return 301 https://$host$request_uri;
不要手动加 /,$request_uri 已经包含了。
原因三:HTTPS server 块里没有对应的 location 匹配
如果你的 Nginx 配置里 HTTPS server 块用了正则 location 或特定路径匹配,而跳转后的 URL 恰好匹配不到任何 location,就会返回 404。
典型场景:HTTPS 站点用了反向代理,但 proxy_pass 的路径和跳转后的 URI 对不上。
# HTTPS server 块
server {
listen 443 ssl;
server_name www.example.com;
location /app/ {
proxy_pass http://backend:8080/;
}
}
如果跳转后的地址是 https://www.example.com/path?param=1,而 /path 没有对应的 location,就会 404。
排查方法:用 nginx -T 导出完整配置,检查 HTTPS server 块里是否有 location / 兜底,或者是否有正确的 proxy_pass 配置。
原因四:URL 编码参数导致路径解析异常
某些特殊字符(如 %、#、? 等)在查询参数里如果没有正确编码,Nginx 可能会把参数的一部分当作路径来处理,导致 404。
例如原始请求是:
http://example.com/search?q=hello%20world
如果 %20 被错误解码或编码,跳转后路径可能变成 /search?q=hello world(空格未编码),Nginx 无法正确解析,返回 404。
排查方法:用浏览器开发者工具查看 Network 面板,看跳转后的实际请求 URL 是什么,是否有乱码或异常字符。
原因五:CDN 或负载均衡在中间修改了请求路径
如果你的站点前面有 CDN(如 Cloudflare、阿里云 CDN)或负载均衡器,它们可能会在转发请求时修改 URI,导致后端 Nginx 收到的路径和预期不一致。
Cloudflare 的"始终使用 HTTPS"功能如果和 Nginx 自己的 return 301 同时开启,可能导致双重跳转,参数在中间丢失或路径被改写,最终 404。
排查方法:用 curl -vL http://your-site.com/path?param=1 查看完整的跳转链路,看每一跳的响应是什么,在哪一步出现了 404。
正确的 return 301 保留参数配置模板
综合上述排查,这里给出一个经过验证的安全配置模板:
# HTTP server 块:跳转 HTTPS 并保留所有参数
server {
listen 80;
server_name www.example.com example.com;
return 301 https://www.example.com$request_uri;
}
# HTTPS server 块:确保 root 和 location 配置正确
server {
listen 443 ssl http2;
server_name www.example.com;
root /var/www/html;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
# 如果是 PHP 站点
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
快速排查清单
- 直接访问 HTTPS 地址(不带参数)是否 404?→ 检查 root/index 配置
- 跳转后的 URL 是否有双斜杠(//)?→ 检查 $request_uri 前是否多了 /
- HTTPS server 块是否有 location / 兜底?→ 用 nginx -T 检查
- 跳转后 URL 是否有异常字符?→ 用 curl -vL 查看实际跳转链路
- 前面是否有 CDN?→ 检查 CDN 的 HTTPS 跳转配置是否和 Nginx 冲突
相关文章
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论