swoft 學習筆記之異常處理

zs4336 發表於2019-08-13

異常處理包含定義異常類和與之對應的異常處理類,處理類通常包含名字為 handle 的方法

一、定義異常類

<?php

namespace App\Exception;

Class ApiException extends \Exception {

}

二、定義異常處理類

<?php

namespace App\Exception\Handler;

use App\Exception\ApiException;
use Swoft\Error\Annotation\Mapping\ExceptionHandler;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Exception\Handler\AbstractHttpErrorHandler;

/**
 * @ExceptionHandler(ApiException::class)
 */
class ApiExceptionHandler extends AbstractHttpErrorHandler
{
    /**
     * @param \Throwable $e
     * @param Response $response
     * @return Response
     * @throws \ReflectionException
     * @throws \Swoft\Bean\Exception\ContainerException
     */
    public function handle(\Throwable $e, Response $response): Response
    {
        $data = [
            'code'  => -1,
            'msg'   => $e->getMessage()
        ];
        return $response->withData($data);
    }
}

三、HTTP異常接管

當在做 API 開發的時候,後端第一個要做的就是驗證引數的合法性。當引數不合法時,會返回給客戶端具體錯誤資訊,此時是通過丟擲異常的方式。因此我在系統自帶的異常處理類裡面稍微做了些修改。具體修改思路是:如果丟擲的異常時驗證類的異常,則直接返回給客戶端錯誤資訊,如果不是的話,再判斷當前環境是開發除錯還是生產,如果是除錯生產,則丟擲具體錯誤資訊,方便除錯,如果是生產環境,則沒必要把詳細的錯誤資訊返回給客戶端,因為客戶端根本不關心具體錯在哪了,此時需要統一返回服務端內部錯誤就行,並視情況而定,到底是否需要記錄日誌。

<?php declare(strict_types=1);

namespace App\Exception\Handler;

use const APP_DEBUG;
use function get_class;
use ReflectionException;
use function sprintf;
use Swoft\Bean\Exception\ContainerException;
use Swoft\Error\Annotation\Mapping\ExceptionHandler;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Exception\Handler\AbstractHttpErrorHandler;
use Swoft\Log\Helper\CLog;
use Throwable;
use App\Model\Struct\DataStruct;
use App\Model\Struct\ConstantStruct;
use Swoft\Validator\Exception\ValidatorException;

/**
 * Class HttpExceptionHandler
 *
 * @ExceptionHandler(\Throwable::class)
 */
class HttpExceptionHandler extends AbstractHttpErrorHandler
{
    /**
     * @param Throwable $e
     * @param Response $response
     *
     * @return Response
     * @throws ReflectionException
     * @throws ContainerException
     */
    public function handle(Throwable $e, Response $response): Response
    {
        // Log
        CLog::error($e->getMessage());

        //如果是驗證類異常,則返回給客戶端,不需要記錄日誌
        if( $e instanceof ValidatorException ){
            $data = [
                'code' => ConstantStruct::VALIDATOR_ERROR,
                'msg'  => $e->getMessage(),
            ];

            return $response->withData($data);
        }

        //如果是系統內部異常,則判斷是否是環境測試還是生產
        //如果是非 debug 模式,則統一丟擲系統內部錯誤
        if ( ! APP_DEBUG ) {

            $data = [
                'code' => ConstantStruct::CODE_ERROR,
                'msg'  => $e->getMessage(),
            ];

            return $response->withData($data);
        }

        //如果是 debug 模式,就丟擲具體錯誤資訊,便於除錯
        $data = [
            'code'  => $e->getCode(),
            'error' => sprintf('(%s) %s', get_class($e), $e->getMessage()),
            'file'  => sprintf('At %s line %d', $e->getFile(), $e->getLine()),
            'trace' => $e->getTraceAsString(),
        ];
        return $response->withData($data);
    }
}

趁還沒掉光,趕緊給每根頭髮起個名字吧~