前言
和PHP默认的异常处理不同,ThinkPHP抛出的不是单纯的错误信息,而是一个错误页面。
如果是做web开发,给客户端返回这种错误页面还好;但如果是做API开发的话,返回这个页面客户端根本无法处理,所以我们需要对异常进行捕获处理。
异常分类
用户行为导致的异常
没有通过验证器、没有查询到结果。
通常不需要记录日志,需要向用户返回具体信息。
服务器自身的异常
代码错误、调用外部接口错误。
通常需要记录日志,不需要向客户端返回具体原因。
try-catch
相信对于大部分人而言,try-catch并不陌生。
使用try-catch我们可以在可能发生异常的地方进行异常捕获,然后对异常进行后续处理,返回给客户端可以处理的错误信息。
实例
try{
// 可能发生异常的业务逻辑
}
catch(Exception $ex){
// RESTful风格的错误返回信息
$err = [
'error_code'=>10001,
'msg'=>$ex->getMessage()
];
// 返回json格式的错误信息,并且规定HTTP状态码
return json($err,400);
}
try-catch这种异常捕获方式存在以下问题:
-
逐层抛出,如果是最底下的业务逻辑出现了问题会将异常逐层抛出,否则就会直接被原有的默认异常捕获到输出一个默认的错误页面;
-
如果是不可预知的异常,未做try-catch处理的业务逻辑,就会输出一个默认的错误页面;
-
某些错误信息不适合直接返回给客户端,需要做统一处理。
总结起来就是繁琐,不够健壮。
构建Validate层
实现步骤大致为:
-
自定义错误处理器——ExceptionHandler。
-
config.php的exception_hadle配置项修改为上面的自定义错误处理器。
-
创建基础异常处理类——BaseException。
-
创建具体异常处理类——xxxException。
错误处理器——ExceptionHandler
1)模块同级目录下,创建lib/exception文件夹
2)创建ExceptionHandler,继承think\exception\Handle
3)引用Exception类
4)重写render方法
我们定义,凡是继承了BaseException的异常,就属于用户导致的异常。
namespace app\lib\exception;
// 引用框架的Exception
use Exception;
// 引用Log类
use think\facade\Log;
// 引用Request类
use think\facade\Request;
// 引用框架的Handle
use think\exception\Handle;
class ExceptionHandler extends Handle
{
private $code;
private $msg;
private $errorCode;
// 重写框架的render方法
public function render(Exception $e){
// 如果是用户类错误
if($e instanceof BaseException){
$this->code = $e->code;
$this->msg = $e->msg;
$this->errorCode = $e->errorCode;
}
// 如果是服务器内部错误
else{
$switch = config('app.app_debug');
// 开发模式下显示html页面
if($switch){
return parent::render($e);
}
// 生产模式下显示json数据
else{
$this->code = 500;
$this->msg = '服务器内部错误,不想告诉你';
$this->errorCode = 999;
// 写入日志
$this->recordErrorLog($e);
}
}
// 返回数组
$result = [
'msg' => $this->msg,
'errorCode' => $this->errorCode,
'request_url' => Request::url()
];
return json($result,$this->code);
}
// 服务器内部错误信息写入日志
private function recordErrorLog(Exception $e){
Log::write($e->getMessage(),'error');
}
}
基础异常处理类——BaseException
1)引用Exception类。
2)定义通用异常错误的属性(http状态码、错误信息、自定义错误码)。
3)构造函数可以传值,覆盖默认属性。
namespace app\lib\exception;
use Exception;
class BaseException extends Exception
{
// 默认HTTP状态码
public $code = 400;
// 默认错误提示信息
public $msg = '参数错误';
// 默认业务错误码
public $errorCode = 10000;
// 构造函数
public function __construct($params = [])
{
// 判断是否数组
if(!is_array($params)){
return;
}
// 判断是否有code、errorCode、msg这些参数代入
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'];
}
}
}
具体异常处理类
1)新建对应异常类,继承BaseException。
2)定义具体的异常错误属性。
namespace app\lib\exception;
class BannerMissException extends BaseException
{
// HTTP状态码
public $code = 404;
// 提示错误信息
public $msg = '请求的banner不存在';
// 自定义错误码
public $errorCode = 40000;
}