「FastAPI实战」请求与响应核心机制全解析

一、FastAPI请求处理机制详解

1.1 路径参数与类型注解

FastAPI通过Python类型注解实现自动参数解析,路径参数需在路由路径中用花括号{}定义,并在函数参数中声明类型:

  1. from fastapi import FastAPI
  2. app = FastAPI()
  3. @app.get("/items/{item_id}")
  4. async def read_item(item_id: int): # 类型注解触发自动转换
  5. return {"item_id": item_id, "type": "integer"}

当访问/items/5时,FastAPI自动将字符串”5”转为整数。支持类型包括intfloatstrbool及自定义类型。

1.2 查询参数处理

查询参数通过函数参数直接声明,支持默认值和可选参数:

  1. @app.get("/search/")
  2. async def search_items(
  3. query: str, # 必选参数
  4. limit: int = 10, # 可选参数带默认值
  5. sort: str = None # 可选参数
  6. ):
  7. results = {"query": query, "limit": limit}
  8. if sort:
  9. results["sort"] = sort
  10. return results

访问/search/?query=test&limit=5&sort=asc时,参数自动绑定到对应变量。

1.3 请求体解析(Pydantic模型)

对于JSON请求体,需定义Pydantic模型实现数据验证:

  1. from pydantic import BaseModel
  2. class Item(BaseModel):
  3. name: str
  4. description: str | None = None
  5. price: float
  6. tax: float | None = None
  7. @app.post("/items/")
  8. async def create_item(item: Item):
  9. item_dict = item.dict() # 转换为字典
  10. if item.tax:
  11. price_with_tax = item.price + item.tax
  12. item_dict.update({"price_with_tax": price_with_tax})
  13. return item_dict

发送POST请求时,FastAPI自动验证JSON结构,缺失必填字段会返回422错误。

二、响应处理进阶技巧

2.1 响应模型控制

通过response_model参数精确控制返回字段:

  1. @app.get("/items/{item_id}", response_model=Item)
  2. async def read_item(item_id: int):
  3. return {"name": "Test", "price": 10.5, "description": "Test item"}
  4. # 即使返回字典,也会按Item模型过滤字段

2.2 自定义响应

使用Response对象直接控制响应头和状态码:

  1. from fastapi import Response
  2. @app.get("/download/")
  3. async def download_file():
  4. content = b"Binary file content"
  5. headers = {"Content-Disposition": "attachment; filename=test.bin"}
  6. return Response(content, headers=headers, media_type="application/octet-stream")

2.3 流式响应

处理大文件或实时数据时使用生成器:

  1. @app.get("/stream/")
  2. async def stream_data():
  3. def generate():
  4. for i in range(10):
  5. yield f"Data chunk {i}\n"
  6. return StreamingResponse(generate(), media_type="text/plain")

三、生产级实践建议

3.1 路径操作装饰器组合

合理使用多个装饰器处理不同HTTP方法:

  1. @app.get("/items/{item_id}")
  2. @app.put("/items/{item_id}")
  3. async def update_item(item_id: int, item: Item):
  4. # 共用逻辑处理
  5. return {"item_id": item_id, **item.dict()}

3.2 依赖注入系统

使用Depends实现跨路由共享逻辑:

  1. from fastapi import Depends, Header, HTTPException
  2. async def verify_token(x_token: str = Header(...)):
  3. if x_token != "fake-token":
  4. raise HTTPException(status_code=403, detail="Invalid token")
  5. return x_token
  6. @app.get("/secure/")
  7. async def secure_endpoint(token: str = Depends(verify_token)):
  8. return {"token": token}

3.3 性能优化技巧

  • 对静态文件使用StaticFiles
  • 启用ASGI服务器(如Uvicorn)的异步特性
  • 使用@cache装饰器缓存响应

四、完整示例:订单处理API

  1. from fastapi import FastAPI, Path, Query
  2. from pydantic import BaseModel, EmailStr
  3. from typing import Optional, List
  4. app = FastAPI()
  5. class OrderItem(BaseModel):
  6. product_id: int
  7. quantity: int = Query(1, ge=1)
  8. class Order(BaseModel):
  9. customer_email: EmailStr
  10. items: List[OrderItem]
  11. discount: Optional[float] = 0.0
  12. @app.post("/orders/")
  13. async def create_order(order: Order, user_agent: Optional[str] = Header(None)):
  14. total = sum(item.quantity * 10.0 for item in order.items) # 假设单价10
  15. discounted_total = total * (1 - order.discount)
  16. return {
  17. "order_id": 1000 + len(app.state.orders) if hasattr(app.state, 'orders') else 1000,
  18. "total": total,
  19. "discounted_total": discounted_total,
  20. "user_agent": user_agent
  21. }
  22. @app.get("/orders/{order_id}")
  23. async def get_order(
  24. order_id: int = Path(..., ge=1000),
  25. include_items: bool = Query(True)
  26. ):
  27. base_order = {"order_id": order_id, "status": "processed"}
  28. if include_items:
  29. base_order["items"] = [{"product_id": 1, "quantity": 2}]
  30. return base_order

五、常见问题解决方案

  1. 参数解析失败:检查类型注解是否正确,使用str接收无法转换的值
  2. CORS问题:添加@app.middleware("http")或使用fastapi.middleware.cors.CORSMiddleware
  3. 性能瓶颈:用anyio进行并发处理,避免同步IO操作
  4. 版本控制:在路由前缀中添加版本号,如@app.get("/v1/items/")

通过系统掌握这些核心机制,开发者能够快速构建出符合企业级标准的RESTful API。建议结合FastAPI官方文档和Pydantic模型验证文档进行深入学习,同时利用Swagger UI(访问/docs)进行交互式测试。