err_too_many_redirects源于nginx重写规则死循环,核心表现为rewrite无条件重复匹配、proxy_pass未透传x-forwarded-proto导致后端误判协议,或location配置不当引发反复内部重定向;需查错误日志中“rewrite or internal redirection cycle”线索,用curl验证跳转链,并修正rewrite逻辑与代理头传递。

浏览器提示“ERR_TOO_MANY_REDIRECTS”或“重定向次数过多”,基本说明 Nginx 的 rewrite 规则触发了死循环。这不是浏览器问题,而是请求在 Nginx 内部反复跳转、超过默认 10 次限制后被强制终止,返回 500 错误(或由浏览器拦截并报错)。排查核心是定位哪条 rewrite 在反复执行、为何无法退出。
看错误日志抓关键线索
直接打开 Nginx 错误日志,搜索这两行:
- “rewrite or internal redirection cycle” —— 这是死循环的明确信号,出现即确认问题存在
-
“internally redirecting to "/xxx"” —— 显示最终卡住的 URI,比如
/index.php或/login,这就是循环落点
再往上翻几行,找到对应请求的 client、request 字段,还原原始访问路径(如 GET / HTTP/1.1),确认是不是首页、API 路径或静态资源触发的。
查 rewrite 规则是否无条件重复匹配
常见错误是 rewrite 没加判断,每次请求都执行,且重写后的路径又命中同一个 location。例如:
- location / { rewrite ^/(.*)$ /index.php?$1 last; } —— 如果
/index.php本身也落在这个location /下,就会反复进入 - rewrite ^/old/(.*)$ /new/$1 last; 配合 location /new/ { ... },而 /new/ 块里又有同名 rewrite
解决方向:
- 把
last改成break(内部改写不重新匹配) - 用更精确的 location,比如
location ^~ /old/或正则location ~ ^/old/,确保新路径不落入其中 - 加 if 判断原始 URI,避免二次处理:
if ($request_uri ~ ^/old/) { rewrite ^/old/(.*)$ /new/$1 break; }
用 curl 验证真实跳转行为
浏览器会缓存 301、自动重试,干扰判断。用 curl 看原始响应头:
-
curl -I http://yourdomain.com/—— 查看是否返回 301/302 及 Location 头内容 -
curl -v http://yourdomain.com/—— 观察完整跳转链,看是否连续返回相同 Location - 重点比对:Location 是
http://还是https://?是否包含域名?是否协议与原始请求不一致?
如果看到 Location 总是 http://yourdomain.com/,但你访问的是 HTTPS,说明 rewrite 或后端重定向强行降级了协议。
检查变量和 proxy_pass 配合是否出错
当 rewrite 用于反向代理前路径改写时,容易因变量为空或 proxy_pass 尾部斜杠缺失引发循环:
- rewrite 中用了未定义变量(如
$undefined_var),结果变成空路径,如重写为/,又回到根 location -
proxy_pass http://backend;(不带斜杠) + rewrite 去前缀 → 后端收到完整路径;若写成proxy_pass http://backend/;(带斜杠)→ 会切掉匹配部分,路径可能错位 - 没透传
X-Forwarded-Proto,导致后端以为是 HTTP 请求,自己又返回 301 跳 HTTPS,外层再跳一次,形成闭环
建议在对应 location 中加上:proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Host $host;
临时启用调试日志看清每一步
默认 error_log 不显示 rewrite 执行过程。要看到逐跳记录:
- 确认 Nginx 编译含
--with-debug(执行nginx -V | grep debug) - 在 http 块中加:
error_log /var/log/nginx/debug.log debug; - 重启后复现问题,执行:
tail -f /var/log/nginx/debug.log | grep -i "rewrite\|redirect\|phase"
你会看到类似:*123456 rewrite phase: 3, "/api/user" -> "/index.php"*123456 http finalize request: 500
清楚显示哪条规则在反复触发。











