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