重定向循环与 HTTPS 识别错乱:X-Forwarded-Proto 那些坑

来源:互联网 时间:2026-09-06

HTTPS 证书配好、Nginx 强制跳转也配好了,浏览器打开却提示 ERR_TOO_MANY_REDIRECTS,重定向次数超限。这个故障的高发场景非常固定:网站前面挂了 CDN、负载均衡或者第二层反向代理。浏览器到 CDN 是 HTTPS,但 CDN 回源到你的 Nginx 走的是 HTTP,于是循环就来了。

拆开看这个循环:你的 Nginx 配了“http 访问就 301 到 https”,可它收到的永远是 http 回源请求,于是每次都 301 跳 https,CDN 又用 http 回源,再收到 301,无限套娃。后端应用也一样倒霉——PHP 里 $_SERVER['HTTPS'] 永远是空的,凡是根据它判断协议的逻辑全部失灵,生成的资源链接全是 http://,又被浏览器的混合内容策略拦一道。

# 断案第一步:看响应头,确认到底在循环什么
curl -sI http://你的域名/ | grep -iE "HTTP/|location"

# 断案第二步:看 Nginx 访问日志里 $scheme 字段,回源请求是不是全是 http
tail -f /var/log/nginx/access.log | awk '{print $6, $9}' | sort | uniq -c

问题本质是协议信息在代理层丢了。标准解法是让代理层把真实协议通过 X-Forwarded-Proto 头传给后端,后端以这个头为准做判断。MDN 对这个头的定义就是:代理服务器用它告诉后端,客户端发起的请求原本是 http 还是 https。

# 代理层(CDN 回源协议改 https,或本层反代):
server {
listen 80;
location / {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:8080;
}
}

# 源站 Nginx:只在“确认客户端真实协议是 http”时才跳转
server {
listen 8080;
set $forward_proto $http_x_forwarded_proto;
if ($forward_proto = "http") {
return 301 https://$host$request_uri;
}
# 正常服务……
}

# PHP 应用侧(以 WordPress 为例,wp-config.php 顶部):
# if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
# $_SERVER['HTTPS'] = 'on';

改完验证别只开浏览器看一眼,用 curl 把整条链路各请求一次:curl -I http:// 应该返回 301 且 Location 是 https;curl -I https:// 应该直接 200,不再出现 Location。如果 CDN 面板里有“回源协议”选项,直接改成 HTTPS 是更干净的做法,连判断逻辑都省了。还有一个容易忽略的点:HSTS 头。如果你配了 Strict-Transport-Security 又想临时回退到 http 调试,浏览器会强制走 https,测试时记得换无痕窗口,不然你看到的“循环”可能只是浏览器缓存了旧跳转。

这类故障的通用心法:凡是链路里出现了代理,所有依赖“客户端长什么样”的判断(协议、真实 IP、Host)都要改成看 X-Forwarded-* 头,并且要在每一层都正确传递。只修一层,问题换个姿势再回来。

相关阅读:重定向循环是接入层和代理层交叉的故障。《服务器故障排查总纲:按现象反查的五层定位法》里与本篇相邻的还有证书链、HTTPS 识别两篇,总纲一张表把关联故障串起来。

相关文章

标签:

A5创业网 版权所有