# 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 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); ```