2018-09-08 14:52:55 3298次浏览 1条回答 1 悬赏 200 金钱

想要自定义错误页面和json响应格式,但是不知道怎么配置。

'errorHandler' => [
    'errorAction' => 'site/error',
],

site控制器下的 actions 方法中 error 也自己定义了返回的 错误类

public function actions()
{
    return [
        'error' => [
//                'class' => 'yii\web\ErrorAction',
            'class' => 'backend\components\helper\ErrorAction',
        ]
    ];
}
<?php
namespace backend\components\helper;
use yii\web\ErrorAction as SystemErrorAction;
use yii\web\NotFoundHttpException;

class ErrorAction extends SystemErrorAction
{
    protected function renderHtmlResponse()
    {
        if (\Yii::$app->user->isGuest) {
            $this->controller->layout = false;
            $this->view = 'no-login-error';
        }
        return $this->controller->render($this->view ?: $this->id, $this->getViewRenderParams());
    }
}

故意输出错误的时候,会显示:An internal server error occurred.

360截图1803052196129114.png
问下怎么能够按照自己想要的错误格式去显示,ajax请求输出json格式。正常的网页请求显示我定义的错误界面。查了资料有的在基类控制器中修改。如果在配置文件中怎么去配置呢?

补充于 2018-09-09 02:27

问题已经解决,
由于有请求我在控制器中没写 FORMAT_JSON ,用了重定向,配置AJAX请求如下:

'response' => [
    'class' => 'yii\web\Response',
    'on beforeSend' => function ($event) {
        /* @var \yii\web\Response $response */
        $response = $event->sender;
        // 这里我们仅针对 ajax 请求
        if ( (request()->isAjax && $response->statusCode == 500)) {
            if($response->format != response()::FORMAT_JSON)
                $response->format = response()::FORMAT_JSON;

            // 手动将抛出异常的状态码改为 200, 确保不被 jQuery 捕获
            $response->statusCode = 200;
            // 自定义错误显示格式,把真正的响应数据存储在 'data' option 内
            $response->data = [
                'code' => 0,
                'data' => '出错了!',
            ];
        }
    },
],

至于 An internal server error occurred. 这个错误是 yii\base\ErrorHandler 抛出的。这个错误很高级,故意配置错数据库,才会显示。在这个基础上在访问一个错的URL 会出现2次重复的这句话,也就是抓到了2次错误。在 yii\base\ErrorHandler类的handleFallbackExceptionMessage方法中 echo 1;exit;都会重复输出。set_exception_handler set_error_handler 这个2个函数搞的鬼。想定制一个抓取所有错误的界面简单点可以搞 web 服务器重定向了。问题过几天在关闭。大家一起讨论。

最佳答案

  • drodata 发布于 2018-09-08 19:24 举报

    你代码中的配置仅对正常的网页请求,ajax 请求的个性化错误信息可通过配置 response 组件实现。你遇到的 500 错误是因为 response 组件在遇到错误时,直接把错误传递到客户端并被 jQuery 捕获。

    可以借助 Response 的 beforeSend 事件改变这种默认的行为:在发送错误前将错误信息进行封装,

    'components' => [
        'response' => [
            'class' => 'yii\web\Response',
            'on beforeSend' => function ($event) {
                $response = $event->sender;
    
                // 这里我们仅针对 ajax 请求
                if ($response->format == \yii\web\Response::FORMAT_JSON) {
                    if ($response->data !== null) {
                        // 手动将抛出异常的状态码改为 200, 确保不被 jQuery 捕获
                        $response->statusCode = 200;
    
                        // 自定义错误显示格式,把真正的响应数据存储在 'data' option 内
                        $response->data = [
                            'success' => $response->isSuccessful,
                            'data' => $response->data,
                        ];
                    }
                }
            },
        ],
    ],
    

    配置后,如果通过 ajax 访问下面的 action,

    // in TestController.php
    public function actionAjaxRead()
    {
        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    
        // 这里将抛出异常
        return 3/0;
    }
    
    $.post("/test/ajax-read", function(response) {
        console.log(response)
    })
    

    响应内容将输出:

    json-error.png

    参考: https://www.yiiframework.com/doc/guide/2.0/zh-cn/runtime-handling-errors#error-format

    6 条回复
    回复于 2018-09-08 22:17 回复

    谢谢了,不过有一个疑问:An internal server error occurred. 在网页不是AJAX请求为什么还会出现呢。

    回复于 2018-09-09 10:35 回复

    errorHandler 组件接管异常处理时,能捕获绝大部分异常,遇到不能识别的异常,才会调用 convertExceptionToArray() 处理。 https://github.com/yiisoft/yii2/blob/master/framework/web/ErrorHandler.php#L107-L132

    "An internal server error occurred" 就是在这个方法内产生的 (https://github.com/yiisoft/yii2/blob/master/framework/web/ErrorHandler.php#L146)

    你说的故意配错数据导致 500 错误出现我没能重现出来。如果故意把数据库密码输入错误,errorHandler 会捕获 yii\db\Exception:

    db-exception.png

    这个异常是通过 site/error 通过 error 视图显示出来的

    回复于 2018-09-09 14:00 回复

    prod环境 不用dev 虽说线上不会出现数据库错误,但是不知道还有没有其他类似的错误。

    回复于 2018-09-09 15:35 回复

    上面的截图是在 prod 下测试的,dev 下显示的是堆栈信息

    回复于 2018-09-09 21:51 回复

    360截图183309148385108.png

    不知道你是怎么配置的。我的就是这样子的。

    回复于 2018-09-20 13:39 回复

    找到原因了。session组件 我配置了 DbSession 所以会抛出 An internal server error occurred. 解决方案就是不配置错数据库,或者 继承 errorHandler 组建 重写屏蔽 handleFallbackExceptionMessage 的echo 输出

    觉得很赞
    没有找到数据。
您需要登录后才可以回答。登录 | 立即注册
小叮当的肚兜
副董事长

小叮当的肚兜

注册时间:2016-10-31
最后登录:13小时前
在线时长:96小时53分
  • 粉丝13
  • 金钱39770
  • 威望270
  • 积分43430

热门问题