如何修复 'ERR_TOO_MANY_REDIRECTS'
通过诊断优先指南修复ERR_TOO_MANY_REDIRECTS,排查重定向循环、HTTP到HTTPS不匹配、Cloudflare SSL和代理设置。
ERR_TOO_MANY_REDIRECTS 表示浏览器跟随了一条永远无法解析的重定向链——最常见的情况是 URL A → URL B → URL A——在达到内置跳转上限后放弃请求。
如果你遇到了这个问题,很可能是修改了某个代理或 SSL 配置,然后发现每个请求都在两个 URL 之间来回跳转,而不是正常加载页面。这个错误令人抓狂,恰恰是因为一小时前页面还运行正常,而且表面上看不出任何问题。这不是浏览器 bug,也不是偶发性故障;它表明你的技术栈中有两条或多条重定向规则对某个 URL 的目标地址存在分歧。本指南以诊断为先:先追踪重定向循环,再修改配置,然后修复真正的根本原因——对大多数开发者来说,根本原因是代理或 CDN 后端的协议不匹配,而不是某个 WordPress 插件。
核心要点
ERR_TOO_MANY_REDIRECTS是一个重定向循环;Chromium 和 Firefox 在跟随 20 次跳转后停止,Safari 停止得更早,随后显示错误而非页面内容。- 在修改任何配置之前先进行诊断:
curl -I -L https://yourdomain.com会打印每次跳转的响应头,循环会以连续的Location:行中相同的两个 URL 交替出现的形式呈现。 - 开发者最常遇到的循环是协议不匹配:代理或 CDN 终止 TLS 后将纯 HTTP 请求转发给源站,而源站强制重定向到 HTTPS,如此循环往复。
- 在 Cloudflare 上,
FlexibleSSL 模式加上”Always Use HTTPS”(或源站强制 HTTPS)必然导致循环;应在安装源站证书后切换至Full (strict)模式。 - 持久性修复方案是在且仅在一个层(框架、Web 服务器或 CDN)中处理 HTTP→HTTPS 和 www/非 www 重定向,而不是在多个层同时处理。
‘ERR_TOO_MANY_REDIRECTS’ 是什么意思?
重定向循环发生在你的站点持续对某个 URL 返回重定向响应,而目标 URL 最终又指回原处,导致浏览器始终无法收到最终的 200 响应。浏览器对跟随跳转的次数有上限:Chromium 和 Firefox 均在 20 次后停止,Safari 停止得更早,此时浏览器放弃请求并显示错误。
不同浏览器的错误提示措辞各异,但以下所有提示描述的都是同一种情况:
| 浏览器 | 错误信息 |
|---|---|
| Chrome | ERR_TOO_MANY_REDIRECTS / “redirected you too many times” |
| Firefox | ”The page isn’t redirecting properly” |
| Edge | ”This page isn’t working right now” |
| Safari | ”Safari Can’t Open the Page” |
重定向本身是普通的 3xx 响应,通常为 301 或 302,每个响应都携带一个 Location 头。在循环中,相同的两个 Location 值交替出现,直到浏览器放弃为止。
诊断优先:追踪重定向链
Discover how at OpenReplay.com.
在修改任何配置之前,先从命令行追踪重定向链。curl -I -L https://yourdomain.com 会打印每次跳转的响应头,循环会以连续的 Location: 行中相同的两个 URL 交替出现的形式呈现。在 curl 手册中,-I(--head)仅获取响应头,-L(--location)则跟随每个 Location 头跳转到下一个 URL。
存在循环的源站会产生如下输出:
HTTP/2 301
location: https://app.example.com/
HTTP/2 301
location: http://app.example.com/
HTTP/2 301
location: https://app.example.com/
...
curl: (47) Maximum (50) redirects followed
这里交替出现的 http:// ↔ https:// 是协议不匹配循环的典型特征。如果同时需要响应体,可使用 curl -sSL -o /dev/null -D - https://yourdomain.com,该命令会输出所有响应头并丢弃响应体。
无需安装工具的替代方案:浏览器 DevTools 的 Network 标签页会显示相同的 301/302 链及每个 Location,Redirect Path 扩展或在线重定向检测工具也可以渲染某个 URL 的重定向链。无论使用哪种输出方式,找到重复出现的 URL——那对交替出现的 URL 就是循环所在。
最常见的开发者问题:SSL 终止导致的 HTTP↔HTTPS 循环
开发者最常遇到的重定向循环并非由插件引起,而是协议不匹配:代理或 CDN 终止 TLS 后将纯 HTTP 请求转发给源站,源站检测到 http 后重定向到 https,如此循环往复。浏览器与边缘节点之间使用 HTTPS 通信;边缘节点与应用之间使用 HTTP 通信;应用”好心地”重定向回 HTTPS。
在 Cloudflare 上,将 SSL/TLS 设置为 Flexible 模式,同时源站也强制 HTTPS,必然导致循环,因为 Flexible 模式始终以 HTTP 连接源站。触发点通常是在 Flexible 模式之上额外开启”Always Use HTTPS”开关。修复方法:在源站安装证书,然后将模式切换为 Full (strict)。当前可用的模式为 Off、Flexible、Full、Full (strict) 和 Strict,而非旧版教程中描述的”三种模式”。
在自建代理或负载均衡器后端,应让应用信任转发的协议头,而不是重新发起重定向。代理应发送 X-Forwarded-Proto 头,携带浏览器原始使用的协议,应用应读取该头而非明文跳转的协议。在 Express 中,启用 trust proxy,使 req.protocol 和 req.secure 反映转发的值:
// Trust the first proxy hop, then req.secure reflects X-Forwarded-Proto
app.set('trust proxy', 1);
app.use((req, res, next) => {
if (!req.secure) {
return res.redirect(301, `https://${req.headers.host}${req.originalUrl}`);
}
next();
});
不设置 trust proxy 时,在 TLS 终止代理后端,req.secure 始终为 false,上述中间件将陷入循环。在 Nginx 中处理源站重定向时,应根据转发的协议进行条件判断,确保规则不会对已经以 HTTPS 到达的流量再次触发:
# Only redirect when the edge saw plain HTTP
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
仅对已登录用户或仅在 CDN 后端触发的生产环境循环,对匿名 curl 请求是不可见的。对受影响会话进行会话回放,可以还原真实用户的 Cookie 和边缘上下文,呈现出那两个来回跳转的 URL,从而重现服务器日志描述但无法直接观察的问题场景。
Cookie 与认证守卫循环
过期 Cookie 和错误路由的认证是第二大常见原因。持有旧重定向状态的 Cookie,或浏览器缓存的 HSTS 策略,可能导致某个客户端陷入循环,而其他用户正常访问——这就是”在普通浏览器窗口中失败,在隐身模式下正常”的症状。首先清除受影响域名的 Cookie 和站点数据。
程序层面的典型案例是认证守卫在自身的登录页上陷入循环。如果 /login 本身也受”将未认证用户重定向到 /login”规则的保护,每次访问都会跳回 /login。解决方法是将登录路由排除在守卫之外。同样的问题也会发生在:登录处理器将用户重定向到受保护页面,而该页面的守卫因 Session Cookie 从未被设置而立即将用户送回——这是上述 req.secure 不匹配的常见副作用,因为 Secure Cookie 会在代理的 HTTP 跳转中被拒绝设置。
重定向规则错误:两个层之间的分歧
重定向循环几乎总是由两个层(框架、Web 服务器和 CDN 各自执行不同的规则)对规范 URL 存在分歧引起的,因此持久性修复方案是在且仅在一个层中处理 HTTP→HTTPS 和 www/非 www 重定向。典型案例:一个层强制添加 www,另一个层去掉 www;某条规则的目标地址仍然匹配自身的触发条件;或者同一条重定向在框架、主机和 CDN 中被重复配置。
框架是一个正式的重定向层,不应被忽视:
- Next.js 在
next.config.js中通过async redirects()定义重定向,其中permanent: true发出308,false发出307。注意,从 Next.js 16 起,旧的middleware文件约定已重命名为 Proxy(proxy.ts);遗留的middleware.ts在 Edge 运行时场景下仍可使用,但已被弃用,将在未来版本中移除,因此其中的重定向或认证逻辑应迁移至proxy.ts。 - Nginx 使用
return 301指令:如上所示,应添加条件判断,防止其在代理后端重复触发。 - Express 使用中间件;在中间件链中保持且仅保持一个 HTTPS 重定向中间件。
- WordPress 是同一模式的一个具体实例:WordPress Address 与 Site Address 设置不一致,本质上就是两个层存在分歧,将两者设置为一致即可解决。
在服务器端,Apache 还可能抛出一个独特的错误:“request exceeded the limit of 10 internal redirects”,其内部重写上限为 10 次,与浏览器的 20 次跳转上限相互独立——这是一个有用的线索,表明循环存在于 .htaccess 中,而非客户端。在 Cloudflare 上,应将 HTTP→HTTPS 重定向配置在现代规则引擎的 Redirect Rule 中;Page Rules 正在被逐步淘汰,由现代规则引擎取代。
如何预防重定向循环?
大多数循环是由配置变更引入的,因此应谨慎进行重定向相关的修改。请参考以下检查清单:
- 每种重定向由且仅由一个层负责。 明确 HTTPS 和 www/非 www 规范化由 CDN、Web 服务器还是应用层处理,并从其他两个层中移除重复配置。
- 信任代理,不要重复重定向。 在任何 TLS 终止节点后端,读取
X-Forwarded-Proto而不是盲目强制 HTTPS。 - 每次修改后重新追踪重定向链。 在任何 HTTPS、域名或 URL 结构变更后,对受影响的 URL 运行
curl -I -L,确认最终以单个200结束。
走出重定向循环最快的路径永远是追踪,而不是猜测。对失败的 URL 运行 curl -I -L,在 Location 响应头中找到来回跳转的两个 URL,然后修复那个”逆流而上”发起重定向的层——最常见的情况是代理将 HTTP 流量转发给坚持使用 HTTPS 的源站。
常见问题
为什么重定向循环在隐身模式下消失,但在普通浏览器窗口中依然存在?
隐身模式启动时不携带任何已存储的 Cookie 或缓存的 HSTS 策略,因此在普通浏览中出现循环、在隐私窗口中消失,指向的是客户端状态问题,而非服务器规则。持有旧重定向状态的过期 Cookie,或强制对配置错误的源站使用 HTTPS 的缓存 HSTS 策略,只会让受影响的浏览器配置文件陷入循环,而其他用户可以正常访问站点。清除该域名的 Cookie 和站点数据;如果怀疑是 HSTS 问题,请检查 chrome://net-internals/#hsts。
Cloudflare Flexible 和 Full (strict) SSL 模式在重定向循环方面有何区别?
Flexible 模式始终以纯 HTTP 从 Cloudflare 连接源站,因此如果源站强制将 HTTP 重定向到 HTTPS,请求将永远循环。Full (strict) 模式以 HTTPS 连接源站并验证受信任的证书,与源站的预期一致,从而打破循环。请先在源站安装有效证书,再将 SSL/TLS 模式从 Flexible 切换为 Full (strict)。在 Flexible 模式上叠加“Always Use HTTPS”开关是常见的触发因素。
为什么 curl 和浏览器对同一 URL 显示不同的重定向行为?
curl 以匿名客户端身份运行,不携带 Cookie、缓存的 HSTS 策略或登录会话,因此它只能重现由服务器或 CDN 规则引起的、对所有请求均生效的循环。依赖特定 Cookie、已认证会话或特定 CDN 边缘节点的循环不会在匿名 curl 追踪中出现。对于这类情况,需要捕获真实用户的上下文:在受影响的会话上使用浏览器 DevTools,或通过会话回放查看在该用户的 Cookie 和认证状态下哪两个 URL 在来回跳转。
Next.js 16 中在 next.config.js 定义的重定向是否适用于通过 Link 或 router.push 进行的客户端导航?
使用 Pages Router 时,在 next.config.js 的 redirects() 函数中定义的重定向,除非存在 Proxy 文件(原 middleware)且匹配该路径,否则不会应用于通过 Link 或 router.push 进行的客户端路由。next.config.js 中的重定向仅在服务器端对完整页面加载和初始请求生效,因此客户端路由切换可以绕过它们。在 Next.js 16 中,middleware 文件约定已重命名为 Proxy(proxy.ts);遗留的 middleware.ts 应当迁移,因为其中遗留的重定向和认证逻辑可能会停止运行。