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()])}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章