101 lines
3.7 KiB
Markdown
101 lines
3.7 KiB
Markdown
# API Scaffold — 分级异常体系
|
||
|
||
> 主流程见 SKILL.md,本文档为异常分级与 AppExceptionHandler 完整实现。
|
||
|
||
## 异常分级
|
||
|
||
| 异常类 | 场景 | HTTP 状态码 | 日志级别 | 是否通知运维 |
|
||
|---|---|---|---|---|
|
||
| `BusinessException` | 可预期的业务错误 | 400/403/404/409/422 | warning | ❌ |
|
||
| `ValidationException` | 参数校验失败 | 422 | info | ❌ |
|
||
| `SystemException` | 不可预期的系统故障 | 500/502/503 | error | ✅ |
|
||
|
||
## BusinessException / SystemException 定义
|
||
|
||
```php
|
||
// app/Exception/BusinessException.php
|
||
class BusinessException extends ServerException
|
||
{
|
||
public function __construct(int $code = 400, string $message = 'Business error', public readonly bool $isOperational = true)
|
||
{
|
||
parent::__construct($message, $code);
|
||
}
|
||
}
|
||
|
||
// app/Exception/SystemException.php
|
||
class SystemException extends ServerException
|
||
{
|
||
public function __construct(string $message = 'System error', int $code = 500, public readonly bool $isOperational = false, ?\Throwable $previous = null)
|
||
{
|
||
parent::__construct($message, $code, $previous);
|
||
}
|
||
}
|
||
```
|
||
|
||
## AppExceptionHandler
|
||
|
||
```php
|
||
<?php
|
||
namespace App\Exception\Handler;
|
||
|
||
use App\Exception\BusinessException;
|
||
use App\Exception\SystemException;
|
||
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||
use Hyperf\Validation\ValidationException;
|
||
|
||
class AppExceptionHandler extends ExceptionHandler
|
||
{
|
||
public function handle(\Throwable $throwable, ResponseInterface $response): ResponseInterface
|
||
{
|
||
$this->stopPropagation();
|
||
$body = match (true) {
|
||
$throwable instanceof ValidationException => ['code' => 422, 'message' => 'Validation failed', 'data' => $throwable->validator->errors()->toArray()],
|
||
$throwable instanceof BusinessException => ['code' => $throwable->getCode(), 'message' => $throwable->getMessage(), 'data' => null],
|
||
$throwable instanceof SystemException => $this->handleSystemException($throwable),
|
||
default => $this->handleUnexpected($throwable),
|
||
};
|
||
$statusCode = ($body['code'] >= 100 && $body['code'] < 600) ? $body['code'] : 500;
|
||
return $response->withStatus($statusCode)->withHeader('Content-Type', 'application/json')
|
||
->withBody(new SwooleStream(json_encode($body, JSON_UNESCAPED_UNICODE)));
|
||
}
|
||
|
||
private function handleSystemException(SystemException $e): array {
|
||
$this->logger->error('System exception', ['message' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
|
||
return ['code' => 500, 'message' => 'Internal server error', 'data' => null];
|
||
}
|
||
|
||
private function handleUnexpected(\Throwable $e): array {
|
||
$this->logger->critical('Unexpected exception', ['class' => get_class($e), 'message' => $e->getMessage()]);
|
||
return ['code' => 500, 'message' => 'Internal server error', 'data' => null];
|
||
}
|
||
|
||
public function isValid(\Throwable $throwable): bool { return true; }
|
||
}
|
||
```
|
||
|
||
## 异常选择决策
|
||
|
||
```
|
||
抛出异常?
|
||
├─ 用户输入/请求导致的?
|
||
│ ├─ 参数格式错误 → ValidationException(FormRequest 自动抛出)
|
||
│ ├─ 资源不存在 → BusinessException(404)
|
||
│ ├─ 无权限 → BusinessException(403)
|
||
│ └─ 业务规则冲突 → BusinessException(409/422)
|
||
└─ 系统/环境导致的?
|
||
├─ 数据库连接失败 → SystemException(503)
|
||
├─ 第三方 API 超时 → SystemException(502)
|
||
└─ 未知异常 → AppExceptionHandler 兜底
|
||
```
|
||
|
||
## Service 使用示例
|
||
|
||
```php
|
||
// Predictable: resource not found
|
||
throw new BusinessException(404, 'Order not found');
|
||
|
||
// Unpredictable: external system failure
|
||
throw new SystemException(message: 'ERP sync failed: connection timeout', previous: $e);
|
||
```
|