recursive_error_pages 不会导致死循环,而是暴露配置中已存在的无终点错误处理链路;它仅在 error_page 指向的 location 再次返回错误时触发,最多10层,超限则返回500。

recursive_error_pages 本身不会导致死循环,但它会暴露和放大你配置中已存在的无终点错误处理链路。所谓“嵌套死循环故障”,其实是 error_page 规则设计不当引发的内部错误反复触发,Nginx 在第 11 层时主动截断并返回 500,日志里写 rewrite or internal redirection cycle——这不是 bug,是保护机制。
它不是循环开关,而是兜底层数限制
recursive_error_pages on 的作用很窄:当某个 error_page 指向的 location 执行后又返回错误码(比如 404、500),Nginx 才会尝试再次查找匹配的 error_page 去接管。这个过程最多 10 次。
它不干预 HTTP 重定向(301/302)、不响应 return 302、也不管 rewrite ... redirect。那些全是客户端行为,和这条指令无关。
真正出问题的地方通常在这几类配置
error_page 无条件指回自身
比如在@fallback里又写error_page 502 = @fallback;,每次失败都进同一个 location,必然超限静态 fallback 路径全部不存在
error_page 404 /fallback/img.png;→ 这个路径没文件,location 里又没做兜底,直接 404 → 再次触发 error_page → 循环PHP 或 FastCGI 错误没被拦截
fastcgi_intercept_errors off(默认)时,PHP 报 500 直接透传给浏览器,Nginx 根本收不到,error_page 500就永远不会触发,你调recursive_error_pages也没用
解决的关键是让每条 fallback 链都有明确终点
-
用
try_files提供静态保底location /img/ { try_files $uri @fallback; } location @fallback { # 先尝试降级路径 try_files /backup/$uri /static/placeholder.png =404; } -
在 fallback location 中直接返回内容,不依赖外部服务
location @fallback { return 200 '{"status":"fallback","code":200}'; add_header Content-Type application/json; } -
用
if或map加判断,避免重复进入map $request_uri $is_fallbacking { ~^/fallback/ 1; default 0; } server { location /api/ { proxy_pass http://backend; error_page 502 = @fallback; } location @fallback { if ($is_fallbacking) { return 503 "Service temporarily unavailable"; } proxy_pass http://backup; } } 配合
proxy_intercept_errors on处理上游错误
如果是代理场景,记得打开这个,否则 upstream 返回的 502/504 不会被 Nginx 拦截,error_page就形同虚设
不复杂但容易忽略

















