TP5 API开发自定义异常类+后台/API通用异常处理方案

TP5/TP5.1框架自带的异常抛出模板内容十分丰富,不仅可以得到准确的错误信息还可以定位到错误行数、代码,以及接收到的各项数据,但是这往往是开发过程中用于排查错误的方式之一,但是开发API中我们在异常处理过程中不可能将这种Html的错误信息返回,那么就需要一种方式可以很方便的用于处理各种异常抛出,例如API请求中异常抛出返回JSON,想要调试时可以返回Html给开发者,再或者是项目正式上线后同样需要分开处理异常。

此文就基于实际项目中遇到的需求讲解一下处理方案。

首先简单说明一下近期接到项目的情况:由于开发进度比较赶所以该项目将后台CMS系统和对接APP的API全部在一个TP5框架下同时开发,首先第一个需求就是在开发过程中需要自定义异常,后台CMS开发需要抛出具体的Html错误模板,API开发时需要抛出Html错误模板用于调试,开发完成后可以抛出JSON,在CMS/API全部开发完成准备上线时只需关闭调试模式即可分别处理不同异常。

首先我们需要定义自己的自定义异常,我的项目中将此自定义异常类放入app目录下,这里lib/exception是自定义目录,可以随意命名。
在这里插入图片描述

首先我们需要在exception中新建一个自定义异常基类,这里起名为BaseException,基本思路也很简单,就是接收到控制器中抛出异常时想要返回的错误码错误信息等,由于我们需求中需要分模块处理,所以我这里加入了一个module字段用于判断异常来自哪个模块,下面贴出完整代码:

<?php
namespace app\lib\exception;
use think\Exception;

/**
 * Class BaseException
 * 自定义异常类的基类
 * @author:Sol
 */
class BaseException extends Exception {
    //状态码
    public $code = 400;
    //错误信息
    public $msg = 'invalid parameters';
    //所属模块名,用于判断后台还是接口,留空为后台admin
    public $module = '';

    /**
     * 构造函数,接收一个关联数组
     * @param array $params 关联数组只应包含code、msg、module,且不应该是空值
     * @author:Sol
     */
    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('module',$params))
        {
            $this->module = $params['module'];
        }
    }
}

这里仅仅是接受到异常信息。具体抛出逻辑需要在自定义一个Handle类,在lib目录下在新建ExceptionHandle类并继承框架中的Handle,我们只需要在抛出规则中判断异常是否来自我们定义的BaseException即可,如果来自BaseException则写我们自己的处理方法,如果不是则正常抛出框架准备的Html模板,代码如下:

<?php
namespace app\lib\exception;
use think\exception\Handle;
use Exception;

class ExceptionHandler extends Handle {
    private $code;
    private $msg;
    public function render(Exception $exception)
    {
        if ($exception instanceof BaseException) {
            $this->code = $exception->code;
            $this->msg = $exception->msg;
            //异常抛出位置来自Api/Admin分开处理
            if ($exception->module == 'api') {
            } else {
                if (config('app_debug')) {
                    return parent::render($exception);
                }
                $this->code = 500;
                $this->msg = '页面发生错误,请稍后再试';
            }
        $result = [
            'code' => $this->code,
            'msg' => $this->msg
        ];
        return json($result);
        }
        else
            return parent::render($exception);
    }
}

相信大家也可以看懂其中逻辑,如果异常位置来自BaseException并且模块为API则抛出Json,若不是API且打开了APP-DEBUG调试模式则返回HTML模板,若关闭调试模式则返回Json错误信息或你想要的前端错误模版。
其中moudle参数的值我们可以通过request()->module();获得。
接下来演示一个实例看一下如何运用这个自定义异常类:

public $userInfoInToken = [];
    public $token = '';
    public $module = '';
    public $getData = '';

    public function _initialize()
    {
        $this->module = request()->module();
        $this->getData = request()->param();
        $this->checkToken($this->getData);
    }

    public function checkToken($getData)
    {
        $headers = request()->header();
        $token = isset($headers['token']) ? $headers['token'] : '';
        if (Db::table('user')->where('id', '=', $getData['id'])->value('token') == $token) {
            $this->token = $token;
            $this->userInfoInToken = Db::table('user')->where('id', '=', $getData['id'])->find();
            return true;
        } else
            throw new TokenException(['module' => $this->module]);
    }

这是用于验证Token的基类控制器,所有API调用前都会执行initalize初始化方法判断Token是否失效,其中TokenException需要继承我们的自定义异常基类BaseException:

<?php
namespace app\lib\exception;
class TokenException extends BaseException
{
    //1000=Token错误 1001=Token信息和请求参数信息不符
    public $code = 1000;
    public $msg = 'Token验证失败';
}

除了这种直接抛出我们同样可以使用try catch来捕获意料外的错误

try
	{}
catch(Exception $e)
	{throw new BaseException(['msg'=>$e->getMessage()])}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章