Files
MrleeAdmin/backend/core/exception/Handler.php
T
2026-08-31 11:33:59 +08:00

188 lines
6.4 KiB
PHP

<?php
namespace core\exception;
use Illuminate\Validation\ValidationException;
use core\jwt\ex\JwtRefreshTokenExpiredException;
use core\jwt\ex\JwtTokenExpiredException;
use core\jwt\ex\JwtTokenInBlacklistException;
use core\jwt\ex\JwtTokenInvalidException;
use FastRoute\BadRouteException;
use core\exception\handler\BaseException;
use core\exception\handler\ServerErrorHttpException;
use think\exception\ValidateException;
use Throwable;
use Webman\Exception\ExceptionHandler;
use Webman\Http\Request;
use Webman\Http\Response;
class Handler extends ExceptionHandler
{
public $dontReport = [];
protected int $statusCode = 200;
protected array $header = [];
protected int $errorCode = -1;
protected string $errorMessage = 'no error';
protected array $responseData = [];
protected array $config = [];
protected string $error = 'no error';
public function report(Throwable $exception)
{
$this->dontReport = config('core.exception.app.handler.dont_report', []);
parent::report($exception);
}
public function render(Request $request, Throwable $exception): Response
{
// Apidoc异常处理响应
// if ($exception instanceof \hg\apidoc\exception\HttpException) {
// return response(json_encode([
// "code" => $exception->getCode(),
// "message" => $exception->getMessage(),
// ], JSON_UNESCAPED_UNICODE), $exception->getStatusCode());
// }
// 处理Laravel验证异常
if ($exception instanceof ValidationException) {
$errors = $exception->errors();
return json([
'code' => 422,
'message' => 'Validation failed',
'data' => $errors,
], 422);
}
$this->initializeConfig();
$this->addRequestInfoToResponse($request);
$this->processException($exception);
$this->addDebugInfoToResponse($exception);
$this->triggerEvents($exception);
return $this->buildResponse();
}
protected function initializeConfig(): void
{
$this->config = array_merge($this->config, config('core.exception.app.handler', []));
}
protected function addRequestInfoToResponse(Request $request): void
{
$this->responseData = array_merge($this->responseData, [
'domain' => $request->host(),
'method' => $request->method(),
'request_url' => $request->method() . ' ' . $request->uri(),
'timestamp' => date('Y-m-d H:i:s'),
'client_ip' => $request->getRealIp(),
'request_param' => $request->all(),
]);
}
protected function processException(Throwable $e): void
{
if ($e instanceof BaseException) {
$this->handleBaseException($e);
} else {
$this->handleOtherExceptions($e);
}
}
protected function handleBaseException(BaseException $e): void
{
$this->statusCode = $e->statusCode;
$this->header = $e->header;
$this->errorCode = $e->errorCode;
$this->errorMessage = $e->errorMessage;
$this->error = $e->error;
if (isset($e->data)) {
$this->responseData = array_merge($this->responseData, $e->data);
}
}
protected function handleOtherExceptions(Throwable $e): void
{
$status = $this->config['status'];
$this->errorMessage = $e->getMessage();
switch (true) {
case $e instanceof BadRouteException:
$this->statusCode = $status['route'] ?? 404;
break;
case $e instanceof ValidateException:
$this->statusCode = $status['validate'] ?? 400;
break;
case $e instanceof JwtTokenInBlacklistException:
case $e instanceof JwtTokenInvalidException:
$this->statusCode = $status['jwt_token'] ?? 401;
break;
case $e instanceof JwtTokenExpiredException:
$this->statusCode = $status['jwt_token_expired'] ?? 401;
break;
case $e instanceof JwtRefreshTokenExpiredException:
$this->statusCode = $status['jwt_refresh_token_expired'] ?? 401;
break;
case $e instanceof \InvalidArgumentException:
$this->statusCode = $status['invalid_argument'] ?? 415;
$this->errorMessage = '预期参数配置异常:' . $e->getMessage();
break;
case $e instanceof ServerErrorHttpException:
$this->statusCode = 500;
$this->errorCode=-1;
break;
default:
$this->statusCode = $status['server_error'] ?? 500;
$this->errorMessage = 'Internal Server Error';
$this->error = $e->getMessage();
break;
}
}
protected function addDebugInfoToResponse(Throwable $e): void
{
if (config('app.debug', false)) {
$this->responseData['error_message'] = $e->getMessage();
$this->responseData['error_trace'] = explode("\n", $e->getTraceAsString());
$this->responseData['file'] = $e->getFile();
$this->responseData['line'] = $e->getLine();
}
}
protected function triggerEvents(Throwable $e): void
{
$this->triggerNotifyEvent($e);
$this->triggerTraceEvent($e);
}
protected function triggerNotifyEvent(Throwable $e): void
{
}
protected function triggerTraceEvent(Throwable $e): void
{
}
protected function buildResponse(): Response
{
$bodyKey = array_keys($this->config['body']);
$bodyValue = array_values($this->config['body']);
// 当HTTP状态码为错误状态时,确保code不为0
$code = $this->errorCode ?: ($bodyValue[0] ?? 0);
if (($this->statusCode >= 400 || $this->statusCode < 100) && $code === 0) {
$code = -1;
}
$responseBody = [
$bodyKey[0] ?? 'code' => $code,
$bodyKey[1] ?? 'msg' => $this->errorMessage,
$bodyKey[2] ?? 'data' => $this->responseData,
];
$header = array_merge(['Content-Type' => 'application/json;charset=utf-8'], $this->header);
return new Response($this->statusCode, $header, json_encode($responseBody));
}
}