自定义404页面拿不到提示信息是因为site/error视图不自动继承session flash消息,需手动读取并渲染;须在views/site/error.php开头引入alert组件,遍历getflash('error')输出,非bootstrap主题应改用原生html渲染。

为什么自定义404页面里拿不到提示信息
因为 site/error 视图默认不自动继承 session flash 消息,而你调用 \Yii::$app->getSession()->setFlash() 存的是 session 级别消息,不是异常对象的一部分。所以即使你在触发 404 前设了 'error' 或 'info' 提示,error.php 里也看不到——除非你手动读取。
如何在 404 页面中显示 setFlash() 提示
必须显式检查并渲染 session flash,不能依赖 $exception 变量。常见错误是只写 if (hasFlash('error')) { echo Alert::widget(...) } 却忘了引入组件或没处理多条消息。
-
use yii\bootstrap\Alert;必须出现在views/site/error.php开头(不是 layout) - 多条消息要遍历:
foreach (\Yii::$app->getSession()->getFlash('error') as $msg) { echo Alert::widget(['body' => $msg]); } - 如果用了非 Bootstrap 主题(比如 AdminLTE),别硬套
Alert::widget(),改用原生 HTML + CSS 渲染:<div class="alert alert-danger">= htmlspecialchars($msg) ?></div> - 注意 XSS:所有从 flash 读出的字符串必须过
htmlspecialchars(),尤其当内容来自用户输入时
为什么设置了 flash 却什么都没显示
最常踩的坑是「404 触发时机早于 flash 设置」。比如你在控制器 action 里先 throw new NotFoundHttpException(),再调 setFlash() —— 后者根本不会执行。异常一抛就跳转到 error handler,后续代码全部跳过。
- 正确顺序:只有在你**手动判断条件失败后、抛异常前**设置 flash,才可能生效(但语义混乱,不推荐)
- 更合理做法:把提示逻辑移到
views/site/error.php内部,根据$exception->statusCode做分支,例如 404 显示“页面找不到了”,500 显示“服务器开小差了” - 调试技巧:在
error.php开头加<?php var_dump(\Yii::$app->getSession()->getFlashes()); die; ?>,确认消息是否真的存在
API 请求下 404 提示怎么统一返回 JSON
Web 页面和 API 共用一个 site/error 行不通。AJAX 或 Accept: application/json 请求进 site/error 会渲染 HTML,前端拿到的是带标签的乱码。
- 必须分流:在
config/web.php的errorHandler配置里,用条件判断切换 errorAction:'errorAction' => Yii::$app->request->getIsAjax() ? 'api/error' : 'site/error' -
api/erroraction 必须返回数组(Yii 自动转 JSON),且不能 echo/print/die - 别在
api/error里调setFlash()——session 对无状态 API 没意义,直接构造['code' => 404, 'message' => 'Not Found']
真正难的不是写 error.php,而是理清「谁在什么时候往哪塞提示」:Nginx 层的 404 塞不了 PHP session,框架层的 NotFoundHttpException 不带 flash,而你手动 setFlash 的时机又很容易被异常打断。留神这些断点,比堆 CSS 更关键。











