Skip to content

异常与响应规范

异常处理规范

异常处理策略

层级核心职责是否使用try-except异常处理方式
API 路由层接收请求、调用 Service、返回统一响应不需要(特殊中间件除外)不处理异常,让异常向上抛至全局兜底
业务服务层实现核心业务逻辑,协调 DB / 第三方服务调用必须使用捕获底层技术异常,抛出自定义业务异常
数据库操作层纯数据库 CRUD 操作,无任何业务判断不使用不处理异常,直接抛给上层服务层

示例

反面例子:路由层处理异常

  • 破坏了分层职责,导致路由层臃肿,且重复定义异常返回格式,破坏全局一致性
python
@router.post("/kb", summary="创建知识库")
async def create_kb(db: AsyncSession, kb_data: KnowledgeBaseCreateSchema):
    try:
        result = await KnowledgeBaseService.create_kb_service(db, kb_data)
        return SuccessResponse(data=result)
    except Exception as e:
        # 错误:路由层处理异常,重复定义返回格式
        return JSONResponse(status_code=400, content={"code": 400, "msg": str(e)})

正确做法:服务层抛异常

  • 不需要在每个路由里写 try-except 来“防止 500” —— 全局兜底已经做了这件事。
  • try-except 应该用在 Service 层(或更靠近业务逻辑的地方),关键是异常的语义转换与业务可读性
  • 核心原则:异常的语义转换。在适当的地方使用 try-except,目的不是“防止程序崩溃”,而是“将底层/第三方异常转化为业务语义明确的自定义异常
python
### API 路由层
@router.post(...)
async def create_kb(...):
    # 不需要 try-except!让异常向上抛
    result = await KnowledgeBaseService.create_kb_service(db, kb_data)
    return SuccessResponse(data=result)


### 业务服务层:捕获底层异常,抛出自定义业务异常
from app.config.exception_config import BusinessException
class KnowledgeBaseService:
    @staticmethod
    async def create_kb_service(db: AsyncSession, kb_data: KnowledgeBaseCreateSchema):
        try:
            # 比如数据库唯一约束冲突、第三方 API 失败等
            kb = KnowledgeBase(name=kb_data.name)
            db.add(kb)
            await db.commit()
            return kb
        except IntegrityError as e:
            # 业务异常
            raise BusinessException(code=400, msg="知识库名称已存在")
        except SomeThirdPartyError as e:
            raise BusinessException(code=502, msg="依赖服务不可用", data=str(e))

相关代码

异常相关代码:app\config\exception_config.py

接口响应规范

统一接口响应

统一业务状态码规范:

  • 成功:code 200
  • 失败:code 非200

统一接口响应配置:app\config\response_config.py

python
from typing import Optional, Generic, TypeVar
from pydantic import BaseModel

T = TypeVar("T")


class SuccessResponse(BaseModel, Generic[T]):
    """
    统一成功响应模型

    业务状态码规范:
    - 成功:code 200
    - 失败:code 非200
    """

    code: int = 200
    msg: str = "成功"
    data: Optional[T] = None

示例

成功

image-20260206113329911

失败

image-20260206113439647