mirror of
http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore.git
synced 2026-01-15 05:15:07 +08:00
205 lines
8.5 KiB
PHP
205 lines
8.5 KiB
PHP
<?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 Singularity\HDK\Core\Exceptions\Handler;
|
|
|
|
use Hyperf\Database\Exception\QueryException;
|
|
use Hyperf\Database\Model\ModelNotFoundException;
|
|
use Hyperf\Di\Annotation\Inject;
|
|
use Hyperf\ExceptionHandler\ExceptionHandler;
|
|
use Hyperf\Framework\Logger\StdoutLogger;
|
|
use Hyperf\HttpMessage\Exception\BadRequestHttpException;
|
|
use Hyperf\HttpMessage\Exception\HttpException;
|
|
use Hyperf\HttpMessage\Exception\MethodNotAllowedHttpException;
|
|
use Hyperf\HttpMessage\Exception\NotFoundHttpException;
|
|
use Hyperf\HttpMessage\Stream\SwooleStream;
|
|
use Hyperf\HttpServer\Contract\RequestInterface;
|
|
use Hyperf\Utils\Codec\Json;
|
|
use Hyperf\Validation\ValidationException;
|
|
use Lmc\HttpConstants\Header;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use RedisException;
|
|
use Singularity\HDK\Core\Constants\CommonErrorCode;
|
|
use Singularity\HDK\Core\Exceptions\ValidateException;
|
|
use Symfony\Component\Mailer\Exception\TransportException;
|
|
use Teapot\StatusCode\RFC\RFC7231;
|
|
use Throwable;
|
|
|
|
/**
|
|
* 通用异常处理
|
|
* Singularity\HDK\Utils\Exceptions\Handler\CommonHandler@hyperf-development-kit
|
|
*
|
|
* @author 李东云<dongyun.li@luxcreo.cn>
|
|
* 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(
|
|
<<<ERROR_LOG
|
|
TYPE: {$error_type}
|
|
[{$data[$code_name]}] {$data[$message_name]}
|
|
{$throwable->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;
|
|
}
|
|
}
|