..
This commit is contained in:
@@ -4,38 +4,105 @@ declare(strict_types=1);
|
||||
|
||||
namespace Aether;
|
||||
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\Context\Context;
|
||||
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||
use Hyperf\Rpc\Protocol;
|
||||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
class RpcExceptionHandler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
|
||||
{
|
||||
// 微服务间调用返回更精简的错误信息
|
||||
$data = [
|
||||
'code' => $throwable->getCode() ?: 500,
|
||||
'message' => $throwable->getMessage() ?: '服务调用失败',
|
||||
'request_id' => Context::get('request_id', ''),
|
||||
];
|
||||
try {
|
||||
// 获取请求ID(用于日志追踪)
|
||||
$requestId = Context::get('request_id', '');
|
||||
|
||||
$protocol = ApplicationContext::getContainer()->get(Protocol::class);
|
||||
$response->getBody()->write($protocol->pack($data));
|
||||
// 从请求中获取可能的RPC ID
|
||||
$rpcId = $this->getRpcIdFromRequest();
|
||||
|
||||
return $response;
|
||||
// 构建符合JSON-RPC 2.0规范的错误响应
|
||||
$errorResponse = [
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => $rpcId ?? $requestId,
|
||||
'error' => [
|
||||
'code' => $throwable->getCode() ?: -32603, // 默认服务器错误码
|
||||
'message' => $throwable->getMessage() ?: 'Internal error',
|
||||
'data' => [
|
||||
'request_id' => $requestId,
|
||||
'exception_type' => get_class($throwable),
|
||||
// 开发环境下可以添加更多调试信息
|
||||
'debug' => env('APP_ENV') === 'dev' ? [
|
||||
'file' => $throwable->getFile(),
|
||||
'line' => $throwable->getLine(),
|
||||
] : null,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// JSON编码
|
||||
$jsonResponse = json_encode($errorResponse, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// 检查JSON编码错误
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$jsonResponse = json_encode([
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => $rpcId ?? $requestId,
|
||||
'error' => [
|
||||
'code' => -32603,
|
||||
'message' => 'Failed to encode error response',
|
||||
'data' => ['request_id' => $requestId],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return $response
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody(new SwooleStream((string) $jsonResponse));
|
||||
} catch (Throwable $e) {
|
||||
$fallbackResponse = json_encode([
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => null,
|
||||
'error' => [
|
||||
'code' => -32603,
|
||||
'message' => 'Fatal error occurred in exception handler',
|
||||
'data' => ['original_error' => $throwable->getMessage()],
|
||||
],
|
||||
]);
|
||||
|
||||
return $response
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withBody(new SwooleStream((string) $fallbackResponse));
|
||||
}
|
||||
}
|
||||
|
||||
public function isValid(Throwable $throwable): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试从请求中获取RPC ID.
|
||||
*/
|
||||
private function getRpcIdFromRequest(): mixed
|
||||
{
|
||||
try {
|
||||
$request = Context::get('hyperf.request');
|
||||
if ($request) {
|
||||
$body = $request->getParsedBody();
|
||||
if (is_array($body) && isset($body['id'])) {
|
||||
return $body['id'];
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
// 获取失败时静默处理
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user