Python后端-FastAPI

3. 请求体解析机制 (Pydantic & Dataclass)

FastAPI 会根据路由函数的参数类型注解,自动解析请求体 JSON 并实例化模型。这一过程发生在你的函数代码执行之前。

FastAPI 只能自动实例化带有结构化字段元数据的类:

python
  ┌────────────────────┬─────────────────────────────────────────┬───────────────────────────┐
  │        类型        │                  示例                   │           能力            │
  ├────────────────────┼─────────────────────────────────────────┼───────────────────────────┤
  │ Pydantic BaseModel │ class NoteCreate(BaseModel): title: str │ ✅ 解析 + 验证 + 错误信息 │
  ├────────────────────┼─────────────────────────────────────────┼───────────────────────────┤
  │ dataclass          │ @dataclass class NoteCreate: title: str │ ✅ 解析(不做强类型验证) │
  ├────────────────────┼─────────────────────────────────────────┼───────────────────────────┤
  │ 普通 classclass NoteCreate: def __init__...       │ ❌ 不支持                 │
  └────────────────────┴─────────────────────────────────────────┴───────────────────────────┘

为什么普通类不支持?

普通类的 init 里可以写任意逻辑(查库、计算、调用 API),FastAPI 无法预知如何把 JSON
映射到它上面。Pydantic 和 dataclass 则通过 annotations 暴露了字段和类型信息,FastAPI
能读取并自动实例化。

执行流

浏览器 POST /notes,Body: {"title": "hello"}

FastAPI 读取签名: def create(note: NoteCreate)

FastAPI 解析 JSON → dict

实例化: NoteCreate(title="hello") ← 验证在这里发生

验证通过 → 调用你的函数: create(note=NoteCreate实例)
验证失败 → 直接返回 422,你的函数不执行

关键点

  • 实例化由 FastAPI 在幕后完成,不是 Python 原生语法。Python 的类型注解本身只起标注作用。
  • 一个路由函数只能有一个 Pydantic/Dataclass 参数(一个请求体)。
  • 函数内拿到的参数已经是实例化后的对象,可直接调用 .model_dump() 等方法。

4. FastAPI 异常处理

4.1 伪代码

python
  # FastAPI 内部实现(伪代码)
class FastAPI:
      handlers = {}

      def exception_handler(self, exc_type):
          def decorator(func):
              self.handlers[exc_type] = func   # 注册 handler
              return func
          return decorator

      # 处理请求时:
      def handle_request(self, request):
          try:
              response = route_handler(request)
          except Exception as exc:
              # 按异常类型找 handler
              handler = self.handlers.get(type(exc))
              if handler:
                  return handler(request, exc)
              # 没匹配到,返回 500
              return JSONResponse(status_code=500, content={"detail": str(exc)})

4.2. 完整流程

python
  @app.exception_handler(NotFoundException)     ← 注册:NotFoundException → handler
  async def not_found_handler(request, exc):
      return JSONResponse(status_code=404, ...)

  notes.py:
      raise NotFoundException("Note")           ← 抛出异常

FastAPI:

代码
  捕获异常 → type(exc) 是 NotFoundException

  → 找到 handler → 调用 not_found_handler(request, exc)

  → 返回 JSONResponse