抛 NotFoundHttpException 是 Yii2 跳转错误页最稳方式;手动 setStatusCode(404) 易因响应头已发送而失效,且 REST 模块会自动覆盖;需确保 errorHandler 配置正确、重写规则无误,并在 error 视图中安全读取 $exception->statusCode。

直接抛 NotFoundHttpException 或其他 HTTP 异常,别手动设状态码——这是 Yii2 跳转错误页最稳的方式。手动调 Yii::$app->response->setStatusCode(404) 极大概率失效,因为响应头可能早已发送或被后续逻辑覆盖。
为什么 setStatusCode(404) 经常不生效
Yii 的 response 对象是延迟写入的,但一旦视图开始渲染、echo 输出、输出缓冲被清空,或调试工具条提前触发了输出,再改状态码就完全无效。常见现象是页面内容正常显示,但浏览器 Network 面板里状态码仍是 200。
- 必须在
action开头或beforeAction()中调用,绝不能在render()之后 - 检查是否有组件(如日志、调试栏)偷偷输出了内容;可在入口脚本加
ob_start()临时验证 - REST 模块(
yii\rest\Controller)会自动根据异常类型设状态码,手动设反而会被覆盖
正确跳转 404 错误页:抛 NotFoundHttpException
这是框架原生支持的方式,能自动触发 errorHandler、渲染对应视图、区分环境,并在 API 场景下返回 JSON。
- 查不到记录时:
if (!$model) throw new \yii\web\NotFoundHttpException('ID 不存在'); - 权限校验失败时更推荐
ForbiddenHttpException,语义更准确 - 确保
config/web.php中已配置'errorHandler' => ['errorAction' => 'site/error'],且该配置在urlManager之前 - 如果抛了异常却看到 Nginx/Apache 默认 404 页,说明请求根本没进 Yii——检查重写规则(Nginx 用
try_files $uri $uri/ /index.php?$args;)和enablePrettyUrl是否开启
error 视图里拿不到 $exception->statusCode?
不是所有异常都有 statusCode。只有 \yii\web\HttpException 子类(如 NotFoundHttpException、BadRequestHttpException)才带这个属性;普通 \Exception 或 \ErrorException 的 statusCode 是 0。
- 在
views/site/error.php开头加<?php var_dump($exception ?? null); die; ?>看实际对象类型 - 安全读取状态码:用
$exception instanceof \yii\web\HttpException ? $exception->statusCode : 500 - 更常见的是 error 视图自身出错(比如调用了未定义的 helper),导致二次异常,最终 fallback 到空白页——先注释掉视图里所有非基础 HTML 再试
真正容易被忽略的点是:错误页本身不能依赖任何可能失败的资源。比如在 error.php 里加载 asset bundle、调用未初始化的 component、或引用 layout 中的动态路径,都会让整个错误处理链崩掉,变成白屏或 500。


















