必须在config/web.php的components中注册自定义errorhandler类,如'app\components\customerrorhandler',并保留erroraction配置以确保renderexception()正确触发视图渲染。

怎么注册自定义 errorHandler 类
必须在 config/web.php 的 components 配置块中显式声明,不能只改控制器或行为。Yii2 的错误分发流程只认这里注册的类:
- 新建类如
app\components\CustomErrorHandler,继承yii\web\ErrorHandler - 在
config/web.php中替换配置项:'errorHandler' => [ 'class' => 'app\components\CustomErrorHandler', 'errorAction' => 'site/error', ], - 务必保留
errorAction,否则renderException()可能不触发视图渲染 - 不要删掉或注释掉整个
errorHandler块,否则会退回到框架默认逻辑
renderException() 为什么返回空白页
重写 renderException() 后页面空白,90% 是因为没走完 Yii 的渲染链路:
- 必须调用
parent::renderException($exception),否则不会自动加载site/error视图 - 方法内不能用
echo、die()或exit(),要返回字符串(比如return $this->render('error', ['exception' => $exception])) - 如果启用了输出缓冲(如
ob_start())或 response 压缩中间件,可能截断内容;开发期建议关掉response.formats中除html外的其他格式 - PHP 致命错误(如 Parse Error)无法被
renderException()捕获,它只处理异常和可捕获错误;这类问题需检查日志或启用display_errors = Off防止裸露代码
API 请求总是返回 HTML 错误页怎么办
Yii2 默认只在 YII_DEBUG = false 且请求头含 Accept: application/json 或是 AJAX 时才返回 JSON,但 Postman/curl 往往不带这个 header:
- 最稳方案:在
web/index.php中(new yii\web\Application($config))->run();前加监听:Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) { if (Yii::$app->request->getContentType() === 'application/json' || Yii::$app->request->isAjax) { Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; } }); - 确保
site/error动作里设置了状态码:Yii::$app->response->statusCode = $exception->statusCode ?: 500; - 返回数组即可,Yii 会自动 JSON 化;别用
json_encode()手动转,否则 status code 会变成 200 - 注意:原生
Exception没有statusCode属性,得兜底判断$exception instanceof \yii\web\HttpException
404 和 500 怎么区分处理
errorAction 是统一入口,但你可以根据异常类型做分支逻辑:
- 在
SiteController::actionError()中检查:if ($exception instanceof \yii\web\NotFoundHttpException)就是 404 - 不要靠 HTTP 状态码数字硬判断(比如
$statusCode === 404),因为$exception->statusCode对非 HttpException 是null - 若要复用视图但差异化渲染,可在视图里用
get_class($exception)或$exception->getName()(部分子类支持)做条件分支 - 更干净的做法是:为不同错误建不同 action,比如
site/error-404,然后在CustomErrorHandler::renderException()里按类型跳转——但要注意,这会绕过errorAction的默认路由机制,需手动 set status 并 render
logException() 却忘了调用 parent::logException($exception),导致错误完全不进日志;还有就是把 errorAction 配错成 'errors/error' 却没建 @app/views/errors/error.php,结果静默 fallback 到白屏。











