美文网首页
全局异常处理(Yii2 做用例)

全局异常处理(Yii2 做用例)

作者: atsukodan | 来源:发表于2019-01-13 00:23 被阅读13次

    首先,我们必须理性认识到,任何一个即使稳定的系统中也是存在着大量的 bug,不管是因为什么原因导致的错误,我们都是需要做好防范的,最好的结果当然是将异常纠正过来,返回客户端一个正确的响应结果,但绝大多数情况下是没办法返回正常结果的,只能返回一个客户端一个异常的信息。
    处理异常的方式,通常分为:

    1. 记录日志
    2. 修复异常
    3. 返回客户端错误

    要处理好这个问题,我认为比较简单的方式就是将需要处理的异常按照场景先做一个分类。


    异常处理场景

    常用的处理是: 用户行为导致的错误通常不需要记录日志,因为若是多人使用的情况下会导致日志量过大,但需要向客户端返回具体原因以便用户用正确的方式调用我们的接口;而服务器出现的错误则需要记录日志,因为我们是需要解决这些错误的,记录日志让我们比较方便的找到错误的原因,快速解决,但不向客户端返回具体原因,因为用户没办法通过自己的行为使异常不再出现。当然我们也可以根据自己的业务决定自己的异常处理方式。

    在 ThinkPHP 或者其他框架中,如果出现异常,则会出现框架的一个异常页面。


    thinkphp异常渲染

    但如果我们开发的是 API,直接返回一个页面给客户端显然不合理,因为别人在使用你的接口的时候还需要解析界面分析出结果,这么做是十分不合理的,所以,我们需要对框架的异常处理进行重写。以下使用 Yii2 框架作为例子讲解重写的逻辑:

    首先,我们需要找到 Yii 框架异常处理的设置(../config/web.php)

    'components'  =>  [
       ..
       'errorHandler' => [
            'errorAction' => 'site/error',
            'class' => 'app\components\ExceptionHandler',(这里配置我们自己写的异常处理方法)
        ],
    ];
    

    为了让我们的程序可以简单的辨别出客户的不当调用导致的错误和服务器的错误,我们可以写一个客户的异常类。新建 library\UserException.php 文件

    class UserException extends Exception {
        // HTTP 状态码 404,200
        public $code = 400;
        // 错误具体信息
        public $msg = '参数错误';
        // 自定义的错误码
        public $errorCode = 10000;
        public function __construct($params) {
            // 如果传过来的不是数组则不进行对象初始化
            if (!is_array($params)) {
                return;
            }
            // 判断数组有没有该键值
            if (array_key_exists('code',$params)) {
                $this->code = $params['code'];
            }
            if (array_key_exists('msg',$params)) {
                $this->msg = $params['msg'];
            }
            if (array_key_exists('errorCode',$params)) {
                $this->errorCode = $params['errorCode'];
            }
        }
    }
    

    新建 components/ExceptionHandler.php 文件,因为 yii 的异常处理的渲染是由 vendor\yiisoft\yii2\web\ErrorHandler.php 中的 renderException 方法渲染的,所以我们开发属于自己的异常处理类的时候可以选择继承该类并重写这个方法。

    class ExceptionHandler extends ErrorHandler {
        public function renderException($exception) {
            if (YII_DEBUG) {
                // 如果为开发模式时,可以按照之前的页面渲染异常,因为框架的异常渲染十分详细,方便我们寻找错误
                return parent::renderException($exception);
            } else {
                // 用户不适当的操作导致的异常
                if ($exception instanceof UserException) {
                    $this->code = $exception->code;
                    $this->msg = $exception->msg;
                    $this->errorCode = $exception->errorCode;
                } else {
                    $this->code = 500;
                    $this->msg = '系统内部出现错误';
                    $this->errorCode = 999;
                    // 记录日志
                }
            }
            $data = [
                'code' => $this->code,
                'msg' => $this->msg,
                'errorCode' => $this->errorCode,
            ];
            echo json_encode($data);
        }
    }
    

    这就完成了全局的异常处理,让我们看看效果

    当我们开启 debug 模式时抛出错误


    debug模式下抛出异常显示

    关闭 debug 模式,抛出服务器端异常

    class BaseController extends Controller {
        public function actionTest() {
            $this->exceptionThrow();
        }
        private function exceptionThrow() {
            throw new \Exception();
        }
    }
    
    非debug模式下抛出服务器端异常

    关闭 debug 模式,抛出客户端异常

    class BaseController extends Controller {
        public function actionTest() {
            $this->exceptionThrow();
        }
        private function exceptionThrow() {
            throw new UserException();
        }
    }
    
    非debug模式下抛出客户端异常

    欢迎关注微信公众号 乱点技能树的小猿
    日常发布初出茅庐程序员一些胡言乱语以及编程资源,漫漫编程路,希望我们一起进步!

    欢迎大家关注

    相关文章

      网友评论

          本文标题:全局异常处理(Yii2 做用例)

          本文链接:https://www.haomeiwen.com/subject/nracdqtx.html