yii2不处理负载均衡错误,因502/504等发生在web服务器与php-fpm之间,请求未达web/index.php,yii_debug和errorhandler均无效;需通过nginx error_log、直连后端及lb健康检查定位。

Yii2 本身不内置负载均衡逻辑,所谓“负载均衡报错”实际是反向代理(如 Nginx、HAProxy)或云服务(如 AWS ALB、阿里云 SLB)在转发请求失败时触发的底层网络/超时错误,Yii2 应用层通常收不到完整异常,只会表现为 502 Bad Gateway、504 Gateway Timeout 或直接空白页 —— 这类错误根本不会进 Yii 的 errorHandler,更不会触发 site/error。
为什么 load balancer 错误不显示 Yii 错误提示
因为这些错误发生在 Web 服务器(Nginx/Apache)与 PHP-FPM 之间,或发生在 LB 与后端应用服务器之间,请求甚至没到达 Yii 入口文件 web/index.php。此时 PHP 进程根本没启动,YII_DEBUG 和 errorHandler 完全无从介入。
-
502:LB 尝试连接后端(如某台 PHP 服务器宕机或 PHP-FPM 崩溃)失败 -
504:LB 等待后端响应超时(常见于慢查询、死锁、长耗时任务未设 timeout) - 空白页 + HTTP 状态码 500:可能是 LB 配置了 fallback 但后端全部不可用,返回了默认错误页
如何让前端用户看到有意义的提示
只能靠 LB 层或 Web 服务器自定义错误页面,Yii 不参与渲染。关键不是改代码,而是配 Nginx 或 LB 控制台:
- Nginx 中配置
error_page 502 504 /50x.html,并确保/50x.html文件存在且可读 - 若用阿里云 SLB,需在控制台「健康检查」页开启「自定义错误页」并上传 HTML
- 不要指望
errorAction => 'site/error'对 502/504 生效 —— 它只处理 PHP 层抛出的异常 - 可在
50x.html里加简单 JS 自动上报错误类型到监控系统(如navigator.onLine+fetch('/api/ping'))
怎么确认真是 LB 问题而不是 Yii 自身崩溃
先排除 Yii 层干扰,快速定位链路断点:
- 绕过 LB,直接用
curl -v http://your-php-server-ip:8080/访问某台后端,看是否返回正常内容 - 查 Nginx error log:
tail -f /var/log/nginx/error.log,搜upstream timed out或no live upstreams - 查 PHP-FPM slow log(如果启用):
grep -i "pool www" /var/log/php7.4-fpm-slow.log - 确认所有后端的
web/index.php开头有error_reporting(E_ALL); ini_set('display_errors', '1');,且YII_DEBUG = true—— 这能帮你区分是 LB 挂了,还是某台后端 PHP 报致命错误导致被 LB 剔除
API 场景下如何避免前端收到 HTML 错误页
当 LB 返回 502/504 时,浏览器或客户端仍会收到 HTML 格式的错误页(如 Nginx 默认 50x.html),这对 JSON API 是灾难性的。必须强制 LB 在检测到请求含 Accept: application/json 时返回纯文本或 JSON:
- Nginx 可用
map指令分流:map $http_accept $json_error { "~*application/json" 1; },再配合error_page 502 = @json_502; - 更稳妥的做法:在 LB 后加一层轻量网关(如 Envoy),统一将 5xx 响应重写为
{"code":502,"message":"Service unavailable"} - 切记:Yii 的
responseFormat = Response::FORMAT_JSON对 LB 错误完全无效 —— 请求根本没进 Yii
真正难处理的从来不是 Yii 怎么显示错误,而是当 LB 把请求悄悄丢掉、不发任何日志、也不触发任何回调时,你得靠 Nginx access log 的状态码分布和后端存活探针交叉验证才能揪出问题节点。











