直接在 config/web.php 中配置自定义 errorHandler 组件即可,需继承 yii\web\ErrorHandler 并重写 renderException() 或 logException() 方法,注意调用 parent:: 方法、返回字符串、区分异常类型及环境限制。

怎么替换 Yii2 默认的 errorHandler 组件
直接在 config/web.php 里重写 errorHandler 组件配置就行,不用改核心类或继承 Application。Yii2 的组件系统支持运行时替换,关键是要保证新类继承 yii\web\ErrorHandler 并正确注册。
- 新建自定义类,比如
app\components\CustomErrorHandler,继承yii\web\ErrorHandler - 重写
renderException()方法处理渲染逻辑,或只重写logException()做日志增强 - 在
components配置中用完整类名替换:'errorHandler' => [ 'class' => 'app\components\CustomErrorHandler', 'errorAction' => 'site/error', ], - 注意:不要删掉
errorAction,否则renderException()可能不触发视图渲染
为什么 renderException() 不生效或页面空白
常见原因是没调用父类逻辑、没返回响应、或被 PHP 错误提前终止。Yii2 的异常处理流程是:捕获 → 日志 → 渲染 → 输出,其中渲染环节容易断在中间。
- 如果你重写了
renderException(),必须显式调用parent::renderException($exception),否则不会走默认视图流程 - 不要在该方法里直接
echo或exit,应返回字符串(如return $this->render('error', [...])) - 若启用了
response缓存或输出压缩(如ob_start),可能吞掉错误内容,建议开发期关掉response.formats中的html外其他格式 - PHP 致命错误(如
ParseError、Fatal Error)不会进renderException(),它们走的是handleFatalError(),这个也得重写
如何让 404 和 500 错误走不同模板
Yii2 默认都走 errorAction 指向的视图(如 site/error),但你可以根据 $exception 类型或 Yii::$app->errorHandler->exception 动态判断。
- 在
site/error视图里检查:if ($exception instanceof yii\web\NotFoundHttpException) { echo $this->render('error-404', ['exception' => $exception]); } else { echo $this->render('error-500', ['exception' => $exception]); } - 更干净的做法是在自定义
CustomErrorHandler::renderException()里提前分发:if ($exception instanceof NotFoundHttpException) { return $this->render('error-404', ...); } - 注意:404 通常由路由或控制器抛出
NotFoundHttpException,而 500 是未捕获异常,类型不同,别用 HTTP 状态码硬判断
自定义 errorHandler 后日志没了或重复记录
因为 logException() 默认会调用 Yii::error(),而你重写时如果漏掉父类调用,或者又手动加了一次 Yii::error(),就会导致漏记或双写。
- 最安全做法:重写
logException()时第一行写parent::logException($exception);,再追加你的逻辑(如上报 Sentry) - 如果只想替换日志渠道(比如只写文件、不写 DB),可以清空
log组件里的targets,或在logException()里直接调用file_put_contents() - 调试时打开
YII_DEBUG = true,并确认log组件已启用,否则Yii::error()什么都不会做
真正麻烦的不是换类,而是异常链里嵌套了 Error(PHP 7+)和 Exception 混用,getPrevious() 可能返回 null 或非 Exception 对象;还有 CLI 环境下 errorHandler 根本不生效——它只对 web application 起作用。








