写FastAPI后端两年,踩过最大的坑不是语法错误,而是那些文档里没写明白的"潜规则"。这篇分享7个真正帮我省下大量调试时间的技巧,每个都带完整代码示例。
1. 部分更新用exclude_unset,别让None覆盖真实数据
![]()
写PATCH接口时,如果只传了name字段,默认情况下Pydantic会把所有可选字段都序列化成None。这意味着email和age会被null覆盖,用户数据莫名其妙就丢了。
![]()
解法是在model_dump()里加exclude_unset=True,这样只返回客户端实际发送的字段:
update_data = body.model_dump(exclude_unset=True)
{"name": "Alice"} 而不是 {"name": "Alice", "email": None, "age": None}
2. HTTPException也能带自定义Header
需要返回401并告诉客户端token过期、多久后重试?别手动拼JSONResponse了,HTTPException直接支持headers参数:
raise HTTPException(
status_code=401,
detail="Token expired",
headers={"X-Error-Code": "TOKEN_EXPIRED", "X-Retry-After": "3600"}
)
代码更干净,错误响应格式也更统一。
3. yield做依赖注入,自动清理资源
数据库连接、文件句柄、临时资源最怕泄露。用yield把依赖拆成"初始化→使用→清理"三段:
async def get_db():
db = await connect_database()
try:
yield db # 这里返回给路由使用
finally:
await db.close() # 响应发送后执行,异常时也会触发
finally块保证即使抛出异常,清理代码也会跑。路由函数里直接db=Depends(get_db)就行,完全不用操心关闭逻辑。
4. 全局异常处理器,告别满屏try/except
每个路由都写try/except是灾难。定义一个AppError异常类,注册全局handler:
@app.exception_handler(AppError)
async def app_error_handler(request: Request, exc: AppError):
return JSONResponse(
status_code=exc.status,
content={"error": {"code": exc.code, "message": exc.message}}
)
路由里直接raise AppError("USER_NOT_FOUND", "...", 404),整个API的错误格式自动保持一致,零样板代码。
5. 文件上传必须服务端校验类型
![]()
客户端校验不可靠。收到UploadFile后,务必检查content_type:
ALLOWED_TYPES = {"image/jpeg", "image/png"}
if file.content_type not in ALLOWED_TYPES:
raise HTTPException(400, "Invalid file type")
别依赖文件名后缀,content_type才是服务端能信任的信息。
6. BackgroundTasks处理异步操作
发送邮件、生成报表这些耗时操作别阻塞响应。FastAPI内置BackgroundTasks:
from fastapi import BackgroundTasks
async def send_email(email: str):
...
@app.post("/signup")
async def signup(user: UserCreate, background_tasks: BackgroundTasks):
background_tasks.add_task(send_email, user.email)
return {"message": "User created"}
响应立即返回,邮件在后台慢慢发。比直接上Celery轻量多了,适合中小项目。
7. 用Depends复用通用校验逻辑
分页参数、权限检查、API版本这些横切关注点,抽成依赖函数:
async def pagination_params(page: int = 1, size: int = 20):
return {"skip": (page-1)*size, "limit": size}
@app.get("/items")
async def list_items(pagination: dict = Depends(pagination_params)):
...
路由代码专注于业务逻辑,通用机制一处定义到处复用。测试时也方便mock掉。
这7个技巧都不是什么高深技术,但文档不会告诉你什么时候该用、坑在哪。踩过才知道,提前知道就能少熬很多夜。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.