前言:个人觉得,学习或温习一套 Web
框架,在快速阅读一遍文档后,应从 路由,控制器,请求 / 响应对象,数据模型(Logic,Dao,Entity),全局异常处理
几个方面下手,这几项了解后,框架上手就游刃有余了。然后我比较喜欢在开工前整理好框架的全局异常处理,方便写 api
时错误的统一响应。
在 api
接口的开发过程中,我们需要对用户数据进行严格的校验,防止非法输入对服务产生安全问题,在开发过程中,我比较喜欢即时的以 抛出异常
的方式中断请求的处理,并以 全局异常处理器
格式化处理后统一返回给客户端。
今天就把 yii2
自带的全局异常处理器改写至对 api
友好(yii2
的 yii\web\HttpException
默认对 web 请求友好,都是以 text/html
的方式返回错误描述,对 api
不友好,api
当然是json
)。
注册异常处理器
yii2
也是以 controller/action
的方式定义一个异常处理器的,我们可以在 components=>errorHandler
中自定义。
# config/web.php
'components' => [
'errorHandler' => ['errorAction' => 'exception/handler']
]
异常处理器
定义相应的异常处理器,app\actions\ErrorApiAction
继承 yii\web\ErrorAction
,可以拿到 yii2
为我们整理好的全局异常。
# controllers/ExceptionController.php
<?php
namespace app\controllers;
use yii\web\Controller;
class ExceptionController extends Controller
{
/**
* 为 actionHandler 挂载独立的 action
* @return array
*/
public function actions()
{
return [
'handler' => ['class' => 'app\actions\ErrorApiAction',]
];
}
}
对 api
友好的错误异常处理器,这里我也只是简单的把响应格式改了一下,异常的上下文还是用 yii2
自带的处理的。
#actions/ErrorApiAction.php
<?php
/**
* @author wangzhijian@styd.com
* @date 2019-5-13 17:20:10
* Api 全局错误异常处理器
*/
namespace app\actions;
use Yii;
use yii\web\ErrorAction;
use yii\web\Response;
class ErrorApiAction extends ErrorAction
{public function run()
{
// 根据异常类型设定相应的响应码
Yii::$app->getResponse()->setStatusCodeByException($this->exception);
// json 格式返回
Yii::$app->getResponse()->format = Response::FORMAT_JSON;
// 返回的内容数据
return ['msg' => $this->exception->getMessage(),
'err' => $this->exception->getCode()];
}
}
异常实体
主要是简单的把状态码的传递封装一下,用更容易理解的类名来代理传递。exceptions/HttpException.php
<?php
/**
* app 异常基础类
*/
namespace app\exceptions;
class HttpException extends \yii\web\HttpException
{public function __construct($message = null, $code = 0, \Exception $previous = null)
{parent::__construct($this->statusCode, $message, $code, $previous);
}
}
exceptions/HttpForbiddenException.php
<?php
/**
* 400 bad request
*/
namespace app\exceptions;
class HttpBadRequestException extends HttpException
{public $statusCode = 400;}
exceptions/HttpUnauthorizedException.php
<?php
/**
* 401 unauthorized
*/
namespace app\exceptions;
class HttpUnauthorizedException extends HttpException
{public $statusCode = 401;}
exceptions/HttpForbiddenException.php
<?php
/**
* 403 forbidden
*/
namespace app\exceptions;
class HttpForbiddenException extends HttpException
{public $statusCode = 403;}
exceptions/HttpNotFoundException.php
<?php
/**
* 404 not found
*/
namespace app\exceptions;
class HttpNotFoundException extends HttpException
{public $statusCode = 404;}
使用范例
在一些 service logic model
中根据需要即时抛出异常即可,上层控制器拿到的永远都是正常的返回数据,绝对的 2xx
响应簇
throw new HttpBadRequestException("具体的非法描述", 4001);
throw new HttpUnauthorizedException("请认证后访问");
throw new HttpForbiddenException("无权访问");
throw new HttpNotFoundException("请求资源不存在");