✨ feat(vscode): 代码阅读加异常卡片,Python、TypeScript 的异常类画成同一张表(属性、构造参数),方法照常是子块

This commit is contained in:
cruldra committed 2026-09-27 10:42:10 +08:00
1 parent d5a092dd6f
commit 0afd012c94
21 files changed
+1118 -66

No files matched your search

@@ -0,0 +1,145 @@
"""自定义异常体系.
所有业务异常继承自 AppException,携带 HTTP 状态码和结构化错误信息。
在 main.py 中注册全局异常处理器统一返回格式。
"""
from __future__ import annotations
from typing import Any
class AppException(Exception):
"""应用异常基类.
Attributes:
status_code: HTTP 状态码。
error_code: 业务错误码(机器可读)。
message: 错误描述(人类可读)。
detail: 额外错误详情。
"""
status_code: int = 500
error_code: str = "INTERNAL_ERROR"
message: str = "服务器内部错误"
def __init__(
self,
message: str | None = None,
*,
detail: Any = None,
error_code: str | None = None,
) -> None:
if message is not None:
self.message = message
if error_code is not None:
self.error_code = error_code
self.detail = detail
super().__init__(self.message)
def to_dict(self) -> dict[str, Any]:
"""序列化为 JSON 响应体."""
body: dict[str, Any] = {
"error_code": self.error_code,
"message": self.message,
}
if self.detail is not None:
body["detail"] = self.detail
return body
class NotFound(AppException):
"""资源不存在 (404)."""
status_code = 404
error_code = "NOT_FOUND"
message = "资源不存在"
class Unauthorized(AppException):
"""未认证 (401)."""
status_code = 401
error_code = "UNAUTHORIZED"
message = "未认证或凭据无效"
class Forbidden(AppException):
"""无权限 (403)."""
status_code = 403
error_code = "FORBIDDEN"
message = "无操作权限"
class ValidationError(AppException):
"""数据验证失败 (422)."""
status_code = 422
error_code = "VALIDATION_ERROR"
message = "数据验证失败"
class ExternalServiceError(AppException):
"""外部服务调用失败 (502)."""
status_code = 502
error_code = "EXTERNAL_SERVICE_ERROR"
message = "外部服务调用失败"
class BusinessError(AppException):
"""业务错误 (400)."""
status_code = 400
error_code = "BUSINESS_ERROR"
message = "业务处理失败"
class Conflict(AppException):
"""资源冲突 (409)."""
status_code = 409
error_code = "CONFLICT"
message = "资源已存在"
class GatewayTimeout(AppException):
"""上游服务响应超时 (504).
用于表达 "请求已发往上游但在时限内未拿到响应":区别于 502
(上游明确报错) 和 503 (上游不可达/未就绪)。
"""
status_code = 504
error_code = "UPSTREAM_TIMEOUT"
message = "上游服务响应超时"
class ServiceUnavailable(AppException):
"""服务暂不可用 (503).
用于表达 "功能依赖的配置/外部资源未就绪" 这类状态:
资源本身合法存在但当前不可达 / 未配置;区别于 404 (资源不存在)
和 502 (上游报错)。
"""
status_code = 503
error_code = "SERVICE_UNAVAILABLE"
message = "服务暂不可用"
class PayloadTooLarge(AppException):
"""请求体超限 (413)."""
status_code = 413
error_code = "PAYLOAD_TOO_LARGE"
message = "压缩包超过 20MB 上限"
class UploadReadTimeout(AppException):
"""上传收流超时 (408)."""
status_code = 408
error_code = "UPLOAD_READ_TIMEOUT"
message = "上传超时, 请检查网络后重试"
+4 -4
View File
@@ -1,10 +1,10 @@
"""领域异常。"""
"""接口响应。"""
from abc import ABCMeta
class AppException(Exception):
"""应用异常的基类。
class AppResponse(BaseModel):
"""应用响应的基类。
带上 HTTP 状态码。
"""
@@ -15,7 +15,7 @@ class AppException(Exception):
self.message = message
class NotFound(AppException): # 行尾
class NotFound(AppResponse): # 行尾
# 说明前面的注释
"""找不到资源。"""
status_code = 404
@@ -0,0 +1,75 @@
"""commerce 域异常体系."""
from __future__ import annotations
class CommerceError(Exception):
"""commerce 域基础异常."""
class ProductNotFoundError(CommerceError):
"""商品不存在或已下架."""
class OrderNotFoundError(CommerceError):
"""订单不存在."""
class InvalidOrderStateError(CommerceError):
"""订单状态非法转换."""
class PaymentVerifyError(CommerceError):
"""支付通道验签失败."""
class AmountMismatchError(CommerceError):
"""支付金额与订单金额不匹配."""
class FulfillmentError(CommerceError):
"""fulfillment 调 billing 失败."""
class RefundError(CommerceError):
"""退款失败."""
class UnsupportedPaymentMethodError(CommerceError):
"""未配置当前 payment_method 对应的 driver. 通常意味着环境变量缺失."""
def __init__(self, method: str) -> None:
super().__init__(f"unsupported payment method: {method}")
self.method = method
class OutOfStockError(CommerceError):
"""商品库存不足, 无法下单。"""
class PurchaseLimitExceededError(CommerceError):
"""超出商品 purchase_limit_per_user 限购次数。"""
class PendingOrderExistsError(CommerceError):
"""同一用户已有相同商品的待支付订单。"""
class ProductPlanMissingError(CommerceError):
"""商品未绑定任何 billing.Plan, 无法下单/履约。"""
class InstanceTypeNotFoundError(CommerceError):
"""instance_type_id 指向的档位不存在; admin 应回 400 而不是撞 FK 500。"""
def __init__(self, instance_type_id: int) -> None:
super().__init__(f"instance_type {instance_type_id} not found")
self.instance_type_id = instance_type_id
class ProductPlanMismatchError(CommerceError):
"""商品展示档位与 Billing Plan 实际发放档位不一致."""
class WechatPayUnknownError(CommerceError):
"""微信预下单结果未知: 网络中断/超时, 不能判定远端是否已受理."""
@@ -0,0 +1,30 @@
/** 调接口出错。 */
export class ApiError extends Error {
status = 500
// 机器可读的错误码
static readonly kind: string = 'API_ERROR'
constructor(message: string, public code?: string) {
super(message)
}
toJSON() {
return { status: this.status, code: this.code }
}
}
export class NotFoundError extends ApiError {
status = 404 // 找不到
}
class Slow extends Timeout {}
class Timeout extends NotFoundError {}
const Cancelled = class extends RangeError {}
export class Forbidden extends errors.HttpException<string> {}
export class Repository extends Base {
status = 1
}