ThinkPHP5之自定義全局異常

爲了針對書寫 api 時,對各類錯誤返回不通的 json ,直接使用 TP5 自帶的提示錯誤頁面,對於客戶端而言,明顯沒有任何的做用,因此須要本身來自定義全局異常。php

1.建立一個全局異常的類(用於傳錯誤信息,狀態碼等)
use think\Exception;
class BaseException extends Exception {
    /** HTTP 狀態碼 * @var string */
    public $code;
    
    /** 自定義錯誤碼 * @var string */
    public $errorCode;
    
    /** 錯誤信息 * @var string */
    public $msg;
    
    public function __construct($params=[]) {
        if (! $params) {
            return ;
        }
        
        // 若是傳了 code
        if ($array_key_exists('code', $code) {
            $this->code = $code;
        }
        
        // 若是傳了 errorCode
        if (array_key_exists('errorCode', $params)) {
            $this->errorCode = $params['errorCode'];
        }

        // 若是傳了 msg
        if (array_key_exists('msg', $params)) {
            $this->msg = $params['msg'];
        }
    }
}
複製代碼

這樣就能夠給以傳不通的狀態碼,錯誤信息和自定義錯誤碼。laravel

2. 建立一個錯誤處理類

錯誤處理類,繼承於TP5自帶的錯誤處理類,重寫該 render 方法,就能夠自定義錯誤。sql

use Exception;
use think\exception\Handle;
use think\Request;

class ExceptionHandle extends Handle {
    /** 狀態碼 * @var */
    private $code;

    /** 自定義錯誤碼 * @var */
    private $errorCode;

    /** 錯誤信息 * @var */
    private $msg;
    
    /** 重寫 Handle 方法裏的Render * @param Exception $e * @return \think\response\Json */
            // 注意這裏是基類 Exception
    public function render(Exception $e) {
        if ($e instanceof BaseException) {
            //若是是自定義異常,則控制http狀態碼,不須要記錄日誌
            //由於這些一般是由於客戶端傳遞參數錯誤或者是用戶請求形成的異常
            //不該當記錄日誌

            $this->msg = $e->msg;
            $this->code = $e->code;
            $this->errorCode = $e->errorCode;
        } else {
            // 若是是服務器未處理的異常,將http狀態碼設置爲500,並記錄日誌
            if (config('app_debug')) {
                // 調試狀態下須要顯示TP默認的異常頁面,由於TP的默認頁面
                // 很容易看出問題
                return parent::render($e);
            }
            $this->code = 500;
            $this->msg = '服務器內部錯誤,不想告訴你';
            $this->errorCode = 999;
            $this->recordErrorLog($e);
        }

        $request = Request::instance();

        $result = [
            'msg' => $this->msg,
            'errorCode' => $this->errorCode,
            'request_url' => $request->url()
        ];
        return json($result, $this->code);
    }
    
    /** 錯誤日誌處理 * 這裏把config裏日誌配置的type改成test * @param Exception $e */
    private function recordErrorLog(Exception $e) {
        // 開啓日誌
        Log::init([
            'type'  =>  'File',
            'path'  =>  LOG_PATH,
            'level' => ['error']
        ]);
        
        // 日誌記錄方法
        Log::record($e->getMessage(),'error');
    }
    
}
複製代碼
3.修改配置config
// 異常處理handle類 留空使用 \think\exception\Handle
    'exception_handle'       => 'app\lib\exception\ExceptionHandle',
    
// 關閉日誌 
'log'                    => [
        // 日誌記錄方式,內置 file socket 支持擴展
        // 關閉自動記錄日誌,請將type設置爲test
        'type'  => 'test',
        // 日誌保存目錄
        'path'  => __DIR__.'/../log/',
        // 日誌記錄級別
        'level' => ['sql'],
    ],
複製代碼
4.使用錯誤類的方法
// 這裏隨便建立一個userControlelr
class UserController extends Controller {

    use app\api\model\User;
    
    /** * 根據 id 獲取某個用戶 */
    public function getUser($id) {
        $user = User::get($id);
        
        // 若是 $user 爲空 拋出自定義的錯誤,下面有...
        if(! $user) {
            throw UserMissException();
        }
        
        return json($user);
    }
}
複製代碼

自定義的錯誤子類json

// 上面第一節,寫的 Base 錯誤類派上用場了。 
class UserMissException extends BaseException {
    /** HTTP 狀態碼 * @var string */
    public $code = '404';

    /** 自定義錯誤碼 * @var string */
    public $errorCode = '40000';

    /** 錯誤信息 * @var string */
    public $msg = '請求的用戶不存在';
}
複製代碼

請求這個 getUser 方法,報錯~ 就會顯示api

{
    "msg": "請求的用戶不存在",
    "errorCode": "40000",
    "request_url": "/api/v1/user/10"
}
複製代碼

其餘的錯誤類型,也就能夠繼續建立異常子類,定義這些錯誤屬性。服務器

5.總結

不光是在TP5的框架,包括laravel框架,也是能夠本身從新寫異常類Exception的render方法,來達到本身想要的錯誤返回數據或者是頁面模版。app

相關文章
相關標籤/搜索