異常處理包含定義異常類和與之對應的異常處理類,處理類通常包含名字為 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);
}
}