展示自定义错误

在Yii中,错误处理是非常灵活的,所以你可以为一种特定的错误创建你自己的错误处理方法。在这个小结中,我们将会以一个非常灵敏的方法处理一个404找不到的错误。我们将会展示一个404页面,它会基于输入栏中输入的内容提供建议的内容。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 添加失败动作到你的SiteController
  1. class SiteController extends Controller
  2. {
  3. // …
  4. public function actionFail()
  5. {
  6. throw new ServerErrorHttpException('Error message example.');
  7. }
  8. }
  1. 添加如下内容到web/.htaccess
  1. RewriteEngine on
  2. RewriteCond %{REQUEST_FILENAME} !-f
  3. RewriteCond %{REQUEST_FILENAME} !-d
  4. RewriteRule . index.php
  1. config/web.php文件中为urlManager组件配置友好的URL:
  1. 'components' => [
  2. // …
  3. 'urlManager' => [
  4. 'enablePrettyUrl' => true,
  5. 'showScriptName' => false,
  6. ],
  7. ],
  1. 对于不存在的URL,展示Not found异常:

展示自定义错误 - 图1

  1. 同时,在我们的actionFail中展示Internal Server Error异常:

展示自定义错误 - 图2

  1. 现在我们希望为Not Found页面创建一个自定义页面。

如何做…

现在我们需要修改Not Found页面的内容,但不考虑其它错误类型。为了达到这个目标,执行如下步骤:

  1. 打开SiteController类并找到actions()方法:
  1. class SiteController extends Controller
  2. {
  3. // ...
  4. public function actions()
  5. {
  6. return [
  7. 'error' => [
  8. 'class' => 'yii\web\ErrorAction',
  9. ],
  10. 'captcha' => [
  11. 'class' => 'yii\captcha\CaptchaAction',
  12. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  13. ],
  14. ];
  15. }
  16. // ...
  17. }
  1. 移除默认的error部分,actions()如下所示:
  1. <?php
  2. class SiteController extends Controller
  3. {
  4. // ...
  5. public function actions()
  6. {
  7. return [
  8. 'captcha' => [
  9. 'class' => 'yii\captcha\CaptchaAction',
  10. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  11. ],
  12. ];
  13. }
  14. // ...
  15. }
  1. 添加自己的actionError()方法:
  1. class SiteController extends Controller
  2. {
  3. // ...
  4. public function actionError()
  5. {
  6. }
  7. }
  1. 打开原始的\yii\web\ErrorAction类,复制它的动作内容到我们的actionError()中,并自定义它用于渲染自定义error-404视图,从而展示404错误码的Not Found错误:
  1. <?php
  2. // ...
  3. use yii\base\Exception;
  4. use yii\base\UserException;
  5. class SiteController extends Controller
  6. {
  7. // ...
  8. public function actionError()
  9. {
  10. if (($exception =
  11. Yii::$app->getErrorHandler()->exception)== null) {
  12. $exception = new HttpException(404, Yii::t('yii',
  13. 'Page not found.'));
  14. }
  15. if ($exception instanceof HttpException) {
  16. $code = $exception->statusCode;
  17. } else {
  18. $code = $exception->getCode();
  19. }
  20. if ($exception instanceof Exception) {
  21. $name = $exception->getName();
  22. } else {
  23. $name = Yii::t('yii', 'Error');
  24. }
  25. if ($code) {
  26. $name .= " (#$code)";
  27. }
  28. if ($exception instanceof UserException) {
  29. $message = $exception->getMessage();
  30. } else {
  31. $message = Yii::t('yii', 'An internal server error occurred.');
  32. }
  33. if (Yii::$app->getRequest()->getIsAjax()) {
  34. return "$name: $message";
  35. } else {
  36. if ($code == 404) {
  37. return $this->render('error-404');
  38. } else {
  39. return $this->render('error', [
  40. 'name' => $name,
  41. 'message' => $message,
  42. 'exception' => $exception,
  43. ]);
  44. }
  45. }
  46. }
  47. }
  1. 使用一个自定义消息添加views/site/error-404.php视图文件:
  1. <?php
  2. use yii\helpers\Html;
  3. /* @var $this yii\web\View */
  4. $this->title = 'Not Found!'
  5. ?>
  6. <div class="site-error-404">
  7. <h1>Oops!</h1>
  8. <p>Sorry, but requested page not found.</p>
  9. <p>
  10. Please follow to <?= Html::a('index page', ['site/index'])?>
  11. to continue reading. Thank you.
  12. </p>
  13. </div>
  1. 现在尝试访问不存在的URL,就能看到error-404.php视图中的内容:

展示自定义错误 - 图3

  1. 但是,对于一个失败的动作,我们能看到error.php文件中默认的内容:

展示自定义错误 - 图4

工作原理…

默认情况下,在yii2-app-basic应用中,我们在配置文件config/web.oho中为errorHandler组件配置errorActionsite/error。这意味着这个框架将会使用这个路由用于展示每一个被处理的异常:

  1. 'components' => [
  2. 'errorHandler' => [
  3. 'errorAction' => 'site/error',
  4. ],
  5. ],

SiteController类中,我们使用内置的yii\web\ErrorAction类,它会渲染所谓的error.php视图:

  1. class SiteController extends Controller
  2. {
  3. // ...
  4. public function actions()
  5. {
  6. return [
  7. 'error' => [
  8. 'class' => 'yii\web\ErrorAction',
  9. ],
  10. 'captcha' => [
  11. 'class' => 'yii\captcha\CaptchaAction',
  12. 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
  13. ],
  14. ];
  15. }
  16. // ...
  17. }

如果我们希望复写它的实现,我们可以 replace it in an inline actionError() method with our own custom content。

在这个小结中,我们添加了自己的if条件,用于渲染一个基于错误码的指定视图:

  1. if ($code == 404) {
  2. return $this->render('error-404');
  3. } else {
  4. return $this->render('error', [
  5. 'name' => $name,
  6. 'message' => $message,
  7. 'exception' => $exception,
  8. ]);
  9. }

同时,我们可以为Not Found页面使用一个自定义设计。

参考

为了了解更多Yii中的错误处理,参考http://www.yiiframework.com/doc-2.0/guide-runtime-handling-errors.html