在项目开发中,我们时常需要去监听全局抛出的异常信息,并在后台根据抛出的异常信息对bug进行修复。那么在Yii2中我们如何去设置呢
1、首先我们需要先创建一个自定义异常类,用于处理全局异常
<?php
namespace app\controllers;
use yii\web\Controller;
use Yii;
use yii\web\NotFoundHttpException;
use yii\web\Response;
use app\exceptions\ApiException;
use app\exceptions\HttpException;
use app\exceptions\ApiException;
use Codeception\Util\HttpCode;
class ExceptionController extends Controller
{
public function __construct($id, $module, $config = [])
{
parent::__construct($id, $module, $config);
}
public function actionErrorHandler()
{
$exception = Yii::$app->errorHandler->exception;
//在这里我们可以将异常保存至异常队列,然后根据反馈信息处理异bug
//对不同的异常抛出有不同的响应处理
switch($exception)
{
case $exception instanceof ApiException:
//响应json
Yii::$app->response->format = Response::FORMAT_JSON;
$data = [
'code' => $exception->getCode(),
'msg' => $exception->getMessage()
];
return $data;
case $exception instanceof HttpException:
//响应视图
return $this->render('error',[
'code' => $exception->getCode(),
'msg' => $exception->getMessage()
]);
case $exception instanceof ApiException:
Yii::$app->response->statusCode = HttpCode::OK;
$data = [
'code' => $exception->getCode(),
'msg' => $exception->getMessage()
];
return $data;
default:
echo 'not get exception';
}
exit;
}
}
2、我们需要在全局配置文件(app/config/web.php)中声明异常处理路径
'components'=>[
//自定义异常处理路径
'errorHandler' => 'exception/error-handler'
]
3、创建两个自定义异常类,用于响应不同类型时,对结果处理。 ApiException(响应JSON数据格式)、HttpException(响应视图数据格式) ApiException
<?php
namespace app\exceptions;
use Throwable;
use yii\base\Exception;
class ApiException extends Exception
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
HttpException
<?php
namespace app\exceptions;
use Throwable;
use yii\base\Exception;
class HttpException extends Exception
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
4、在入口文件(app\web\index.php)中,将当前模式切换为发布模式(目的是模拟发布环境上,确保异常的正常使用)
defined('YII_DEBUG') or define('YII_DEBUG', false);
defined('YII_ENV') or define('YII_ENV', 'prod');
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
$config = require __DIR__ . '/../config/web.php';
(new yii\web\Application($config))->run();
5、测试
public function actionIndex()
{
throw new ApiException('123',123);
//throw new app\exceptions\HttpException('123',123);
}
需要注意的点 1、在抛出异常之前不能更改当前响应数据的格式。例如
Yii::$app->response->format = Response::FORMAT_JSON;
如果这样设置了,那么会导致Yii2抓取不了异常信息
关于如何捕获rest/controller 异常信息
前面我们已经设置了一个全局异常控制器,那么我们希望这个控制器也能捕捉到restFul接口的异常怎么办呢?因为restFul接口继承的控制器是yii\rest\Controller 在抛异常的时候是不会像yii\web\Controller可以控制异常的处理路径的。如下方案解决这个问题。
我们首先创建一个异常 ApiException 用于处理接口异常。
<?php
namespace app\exceptions;
use Throwable;
use yii\base\Exception;
class ApiException extends Exception
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
然后在创建一个类(ApiController)继承 yii\rest\Controller 并在其中添加一个钩子,意为在发送数据给终端用户前,先拦截下来(触发yii\web\Response::EVENT_BEFORE_SEND事件),判断当前响应是否包含异常,如果有异常,使用钩子,去异常处理中心(ExceptionHandlerController)勾出异常处理内容,并响应给客户
<?php
namespace app\modules\v1\common\controllers;
use app\controllers\ExceptionController;
use Yii;
use yii\helpers\ArrayHelper;
use yii\rest\Controller;
class ApiController extends Controller
{
public function __construct($id, $module, $config = [])
{
parent::__construct($id, $module, $config);
$model = $this;
Yii::$app->response->on(yii\web\Response::EVENT_BEFORE_SEND,function($event) use ($model){
if(!empty(Yii::$app->errorHandler->exception))
{
$exception = new ExceptionController($model->id,$model->id);
Yii::$app->response->data = $exception->actionHandler();
}
});
}
public function behaviors()
{
$parentBehaviors = parent::behaviors();
$behaviors = [
];
return ArrayHelper::merge($parentBehaviors,$behaviors);
}
}
|