mirror of
http://124.126.16.154:8888/singularity/HyperfDevelopmentKitCore.git
synced 2026-01-15 07:15:06 +08:00
320 lines
10 KiB
PHP
320 lines
10 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
|
|
{
|
|
/**
|
|
* @Inject(required=false)
|
|
*
|
|
* @var RequestInterface|null
|
|
*/
|
|
private ?RequestInterface $request;
|
|
|
|
/**
|
|
* @Inject
|
|
* @var StdoutLogger
|
|
*/
|
|
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;
|
|
|
|
$error_type = get_class($throwable);
|
|
$request_time = date('Y-m-d H:i:s');
|
|
|
|
if (!empty($this->request)) {
|
|
$this->request->url();
|
|
|
|
$is_debug = $this->request->hasHeader('Postman-Token')
|
|
|| str_starts_with($this->request->header('User-Agent'), 'apifox');
|
|
|
|
$request_data = Json::encode($this->request->getParsedBody());
|
|
$request_headers = Json::encode($this->request->getHeaders());
|
|
} else {
|
|
$is_debug = false;
|
|
$request_data = null;
|
|
$request_headers = null;
|
|
}
|
|
|
|
|
|
|
|
|
|
// 901 程序语法错误
|
|
|
|
// 902 SQL 语法错误
|
|
if ($throwable instanceof QueryException) {
|
|
if ($throwable->getCode() === '42S22') {
|
|
$code = CommonErrorCode::PROGRAM_SQL_COLUMN_NOT_FOUND;
|
|
} else {
|
|
$code = 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' => empty($this->request) ? null : $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());
|
|
$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;
|
|
}
|
|
}
|