* Powered by PhpStorm * Created on 2022/4/28 */ class CommonHandler extends ExceptionHandler { /** * * @var RequestInterface|null */ #[Inject(required: false)] private ?RequestInterface $request; /** * @var StdoutLogger */ #[Inject] private StdoutLogger $logger; /** * {@inheritDoc} */ public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface { // 阻止异常冒泡 $this->stopPropagation(); $restful = config('common.response.restful'); $code_name = config('common.response.code_name'); $message_name = config('common.response.message_name'); $is_testing = config('app_status') === true; $this->request?->url(); $is_debug = $this->request?->hasHeader('Postman-Token') || str_starts_with($this->request?->header('User-Agent'), 'apifox'); $error_type = $throwable::class; $request_time = date('Y-m-d H:i:s'); $request_data = Json::encode($this->request?->getParsedBody()); $request_headers = Json::encode($this->request?->getHeaders()); // 901 程序语法错误 // 902 SQL 语法错误 if ($throwable instanceof QueryException) { $code = match ($throwable->getCode()) { '42S22' => CommonErrorCode::PROGRAM_SQL_COLUMN_NOT_FOUND, default => CommonErrorCode::PROGRAM_SQL_ERROR, }; $data = [$code_name => $code, $message_name => CommonErrorCode::getMessage($is_testing ? $code : CommonErrorCode::PROGRAM_SQL_ERROR)]; if ($is_testing) { $data['details'] = ['sql' => $throwable->getSql(), 'error' => $throwable->getMessage()]; } } // 101 请求方式错误 if ($throwable instanceof MethodNotAllowedHttpException) { $message = explode(': ', $throwable->getMessage()); $allow_method = explode(', ', $message[1]); $code = CommonErrorCode::REQUEST_METHOD_ERROR; $data = [$code_name => $code, $message_name => CommonErrorCode::getMessage($code, ['methods' => join(', ', $allow_method)]), 'currentMethod' => $this->request?->getMethod(), 'allowedMethod' => $allow_method]; } // 验证失败 if ($throwable instanceof BadRequestHttpException) { $data = [$code_name => CommonErrorCode::REQUEST_PARAMS_ERROR, $message_name => $is_testing ? $throwable->getMessage() : CommonErrorCode::getMessage(CommonErrorCode::SERVER_ERROR)]; } if ($throwable instanceof ValidationException) { $data = $throwable->validator->errors()->first(); if (is_numeric($data)) { $code = (int) $data; $data = CommonErrorCode::getMessage($code); } $data = [$code_name => $code ?? CommonErrorCode::REQUEST_PARAMS_ERROR, $message_name => $data]; } if ($throwable instanceof ValidateException) { $code = $throwable->getCode(); $message = $throwable->getMessage(); $data = [$code_name => $code, $message_name => empty($message) ? CommonErrorCode::getMessage($code, ['param' => $throwable->getFieldName()]) : $message]; if ($is_debug) { $data['currentValue'] = $throwable->getCurrentValue(); $data['availableValue'] = $throwable->getAvailableValue(); } } // 路由不存在 if ($throwable instanceof NotFoundHttpException) { $code = CommonErrorCode::ROUTE_NOT_FOUND; $data = [$code_name => $code, $message_name => CommonErrorCode::getMessage($code)]; $status_code = 404; } // 模型不存在 if ($throwable instanceof ModelNotFoundException) { $code = empty($throwable->getCode()) ? CommonErrorCode::MODEL_NOT_FOUND : $throwable->getCode(); $message = empty($throwable->getCode()) ? CommonErrorCode::getMessage($code, ['resource' => '资源']) : $throwable->getMessage(); $data = [$code_name => $code, $message_name => $message]; $status_code = 404; } // 300 服务出错 // 303 缓存异常 if ($throwable instanceof RedisException) { $code = CommonErrorCode::SERVER_CACHE_REDIS_ERROR; if ($throwable->getMessage() === 'Connection refused') { $code = CommonErrorCode::SERVER_CACHE_REDIS_REFUSED_ERROR; } $data = [$code_name => $code, $message_name => CommonErrorCode::getMessage($is_testing ? $code : CommonErrorCode::SERVER_CACHE_REDIS_ERROR)]; } // 306 消息异常 // 30601 邮箱发件异常 if ($throwable instanceof TransportException) { $code = CommonErrorCode::SERVER_MESSAGE_EMAIL_ERROR; if (strpos($throwable->getMessage(), '500 Error: bad syntax')) { $code = CommonErrorCode::SERVER_MESSAGE_EMAIL_NOT_FOUND; } $data = [$code_name => $code, $message_name => CommonErrorCode::getMessage($is_testing ? $code : CommonErrorCode::SERVER_MESSAGE_EMAIL_ERROR)]; } if (empty($data)) { // 其他情况 $data = [$code_name => $is_testing ? $throwable->getCode() == 0 ? CommonErrorCode::SERVER_ERROR : $throwable->getCode() : CommonErrorCode::SERVER_ERROR, $message_name => $is_testing ? $throwable->getMessage() : __(CommonErrorCode::getMessage(CommonErrorCode::SERVER_ERROR))]; // 其他错误 if ($throwable instanceof HttpException) { $data = [$code_name => $throwable->getCode() ?: $throwable->getStatusCode(), $message_name => $throwable->getMessage()]; } } $response = $response->withHeader(Header::CONTENT_TYPE, 'application/json; charset=utf-8'); if ($is_debug && $is_testing) { $data['trace'] = ['errorType' => $error_type, 'errorTrack' => $throwable->getTrace()]; } $cookies = json_encode($this->request->getCookieParams(), JSON_UNESCAPED_UNICODE); $this->logger->error( <<getMessage()} ------------------------------- REQUEST_TIME: {$request_time} ------------------------------- REQUEST_HEADERS: {$request_headers} ------------------------------- REQUEST_COOKIES: {$cookies} ------------------------------- REQUEST_METHOD: {$this->request?->getMethod()} ------------------------------- REQUEST_URL: {$this->request?->getUri()} ------------------------------- REQUEST_QUERY: {$this->request?->getQueryString()} ------------------------------- REQUEST_DATA: {$request_data} ------------------------------- TRACE: {$throwable->getTraceAsString()} =============================== ERROR_LOG ); $data = Json::encode($data); if ($restful) { $response = $response->withStatus($status_code ?? $throwable->status ?? $throwable->statusCode ?? RFC7231::INTERNAL_SERVER_ERROR); } return $response->withBody(new SwooleStream($data)); } /** * 判断该异常处理器是否要对该异常进行处理. */ public function isValid(Throwable $throwable): bool { return true; } }