* * 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 * * 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]; } }