This commit is contained in:
94
app/Exception/Handler/ApiExceptionHandler.php
Normal file
94
app/Exception/Handler/ApiExceptionHandler.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2025/6/3
|
||||
* Time: 下午8:51
|
||||
* Description:
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Exception\Handler;
|
||||
|
||||
use App\Exception\ApiException;
|
||||
use App\Log\Log;
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||
use Hyperf\Validation\ValidationException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2025/6/3
|
||||
* Time: 下午8:54
|
||||
* Description: 统一异常处理
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
class ApiExceptionHandler extends ExceptionHandler
|
||||
{
|
||||
public function __construct(protected ApplicationContext $context)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理异常
|
||||
* @param Throwable $throwable
|
||||
* @param ResponseInterface $response
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$errorData = $this->getErrorData($throwable);
|
||||
|
||||
// 记录日志
|
||||
Log::get('default', 'default')->error($errorData['logMessage']);
|
||||
|
||||
// 阻止异常冒泡
|
||||
$this->stopPropagation();
|
||||
|
||||
return $response->withStatus(200)
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody(new SwooleStream(json_encode($errorData['responseData'], JSON_UNESCAPED_UNICODE)));
|
||||
}
|
||||
|
||||
public function isValid(Throwable $throwable): bool
|
||||
{
|
||||
return $throwable instanceof ApiException || $throwable instanceof ValidationException;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误.
|
||||
*/
|
||||
protected function getErrorData(Throwable $throwable): array
|
||||
{
|
||||
$code = $throwable->getCode();
|
||||
$errorFile = $throwable->getFile();
|
||||
$errorLine = $throwable->getLine();
|
||||
$errorMessage = $throwable->getMessage();
|
||||
|
||||
if ($throwable instanceof ValidationException) {
|
||||
$errors = $throwable->validator->errors()->toArray();
|
||||
$errorMessage = reset($errors)[0];
|
||||
}
|
||||
|
||||
$responseData = [
|
||||
'code' => $code,
|
||||
'message' => $errorMessage,
|
||||
];
|
||||
|
||||
$logMessage = sprintf('%s %s %s %s', $code, $errorFile, $errorLine, $errorMessage);
|
||||
|
||||
return ['responseData' => $responseData, 'logMessage' => $logMessage];
|
||||
}
|
||||
}
|
97
app/Exception/Handler/AppExceptionHandler.php
Normal file
97
app/Exception/Handler/AppExceptionHandler.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
namespace App\Exception\Handler;
|
||||
|
||||
use App\Exception\ApiException;
|
||||
use Hyperf\Contract\StdoutLoggerInterface;
|
||||
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||
use Hyperf\RateLimit\Exception\RateLimitException;
|
||||
use Hyperf\Validation\ValidationException;
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Throwable;
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
/**
|
||||
* Author: ykxiao
|
||||
* Date: 2025/6/3
|
||||
* Time: 下午8:57
|
||||
* Description: 默认异常处理
|
||||
*
|
||||
* (c) ykxiao <yk_9001@hotmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
class AppExceptionHandler extends ExceptionHandler
|
||||
{
|
||||
public function __construct(protected StdoutLoggerInterface $logger)
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(Throwable $throwable, ResponseInterface $response): MessageInterface|ResponseInterface
|
||||
{
|
||||
$this->logException($throwable);
|
||||
|
||||
if ($throwable instanceof RateLimitException) {
|
||||
return $this->handleRateLimitException($response);
|
||||
}
|
||||
|
||||
return $this->handleOtherExceptions($throwable, $response);
|
||||
}
|
||||
|
||||
public function isValid(Throwable $throwable): bool
|
||||
{
|
||||
return ! $throwable instanceof ApiException;
|
||||
}
|
||||
|
||||
protected function createResponseBody($message, $code): StreamInterface
|
||||
{
|
||||
$data = [
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
];
|
||||
return new SwooleStream(json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
protected function logException(Throwable $throwable): void
|
||||
{
|
||||
$this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
|
||||
$this->logger->error($throwable->getTraceAsString());
|
||||
}
|
||||
|
||||
protected function handleRateLimitException(ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$message = '触发请求频率限流规则';
|
||||
return $response->withStatus(429)
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody($this->createResponseBody($message, 429));
|
||||
}
|
||||
|
||||
protected function handleOtherExceptions(Throwable $throwable, ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
$message = $throwable->getMessage();
|
||||
|
||||
if (env('APP_ENV') === 'production' && ! $throwable instanceof ValidationException) {
|
||||
return $response->withStatus(200)
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody($this->createResponseBody($message, 0));
|
||||
}
|
||||
|
||||
return $response->withHeader('Server', 'mes-auto')
|
||||
->withStatus(200)
|
||||
->withBody($this->createResponseBody($message, 0));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user