FastAPI常见错误:新手开发中最容易踩的坑

1. 路径参数与查询参数的混淆

错误场景:定义路由时参数类型未声明,或误用路径参数/查询参数。
错误代码

# 错误:路径参数未声明类型,FastAPI无法推断
@app.get("/users/{user_id}")
async def get_user(user_id):  
    return {"user_id": user_id}  

原因:FastAPI依赖参数类型声明来解析请求,未声明类型会导致参数解析失败(如user_id被当作字符串处理,或前端传数字时报错)。
正确代码

# 正确:路径参数声明类型为int
@app.get("/users/{user_id}")
async def get_user(user_id: int):  
    return {"user_id": user_id}  

解决方法
- 路径参数(URL中{}包裹的参数)必须在函数参数中声明类型(如user_id: int)。
- 查询参数(URL中?key=value形式)可通过Query类设置默认值(如user_id: Optional[int] = None)。

2. 请求体与查询参数的误用

错误场景:用GET请求传复杂数据,或POST请求未使用请求体。
错误代码

# 错误:GET请求用查询参数传“复杂数据”(实际应放在请求体)
@app.post("/items")
async def create_item(item_id: int, name: str):  
    return {"item_id": item_id, "name": name}  

原因:GET请求的参数默认放在查询字符串,不适合传复杂数据;POST请求应通过请求体(Pydantic模型)传递数据。
正确代码

# 正确:用Pydantic模型定义请求体
from pydantic import BaseModel

class Item(BaseModel):
    item_id: int
    name: str

@app.post("/items")
async def create_item(item: Item):  
    return item  

解决方法
- 简单筛选/过滤用查询参数(如/items?name=apple)。
- 复杂数据(如对象、嵌套结构)用POST+Pydantic模型作为请求体。

3. Pydantic模型使用错误

错误场景:模型字段类型错误,或忘记导入BaseModel
错误代码

# 错误1:模型字段类型错误(字符串写成int)
class User(BaseModel):
    name: int  # 前端传字符串会报错
    age: int = 18

# 错误2:未导入BaseModel导致模型定义无效
class Product(BaseModel):  # 报错:BaseModel未定义
    id: int

原因:Pydantic模型需严格定义字段类型,且必须继承BaseModel
正确代码

from pydantic import BaseModel

class User(BaseModel):
    name: str  # 正确类型:字符串
    age: int = 18  # 可选字段带默认值

class Product(BaseModel):
    id: int

解决方法
- 确保模型字段类型与前端传参类型一致(如str/int/float)。
- 必传字段不设默认值,可选字段用Optional[type] = None或直接设默认值。

4. 状态码使用不当

错误场景:成功返回用200(如创建资源),或错误状态码未显式设置。
错误代码

# 错误:创建资源用200状态码(应为201)
@app.post("/users")
async def create_user(user: User):  
    return user  # 状态码默认200,不符合REST规范

原因:RESTful API中,201 Created表示资源创建成功,200 OK通常表示读取/更新成功。
正确代码

from fastapi import status

@app.post("/users", status_code=status.HTTP_201_CREATED)
async def create_user(user: User):  
    return user  # 返回201状态码

解决方法
- 创建资源用201,读取用200,删除用204 No Content
- 错误场景(如资源不存在)用HTTPException指定状态码(如404 Not Found):

  from fastapi import HTTPException

  @app.get("/users/{user_id}")
  async def get_user(user_id: int):  
      if user_id not in [1, 2, 3]:  
          raise HTTPException(status_code=404, detail="用户不存在")  

5. 跨域资源共享(CORS)配置缺失

错误场景:前后端分离时,前端调用API出现“跨域错误”。
错误代码

from fastapi import FastAPI

app = FastAPI()

@app.get("/items")
async def get_items():  
    return {"items": [1, 2, 3]}  

原因:浏览器默认禁止跨域请求(前端域名与后端不同),需配置CORS中间件。
正确代码

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 允许所有前端域名(生产环境建议指定具体域名)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有HTTP方法(GET/POST等)
    allow_headers=["*"],  # 允许所有请求头
)

@app.get("/items")
async def get_items():  
    return {"items": [1, 2, 3]}  

解决方法
- 开发环境用allow_origins=["*"]快速调试,生产环境替换为前端实际域名(如["https://your-frontend.com"])。

6. 异步与同步函数混用

错误场景:在异步依赖中使用同步函数未处理,或同步函数标记为异步。
错误代码

# 错误:异步函数调用同步库未加await
async def get_db():  
    db = create_connection()  # 同步库(如SQLite)
    return db  # 错误:未await同步函数

@app.get("/items")
async def get_items(db=Depends(get_db)):  
    return db.query("SELECT * FROM items")  # 报错:同步库未等待

原因:FastAPI异步函数中调用同步库需用await或转换为异步(如用asyncpg代替psycopg2)。
正确代码

import asyncio

async def get_db():  
    loop = asyncio.get_event_loop()  
    db = await loop.run_in_executor(None, create_connection)  # 同步库异步执行
    return db  

解决方法
- 优先使用异步依赖库(如asyncpghttpx.AsyncClient)。
- 若必须用同步库,用asyncio.run_in_executor在异步上下文中调用。

7. 依赖注入与中间件错误

错误场景:依赖函数未返回、中间件导入错误。
错误代码

# 错误1:依赖函数未返回yield(未用异步上下文管理器)
def get_db():  # 同步依赖未yield
    db = create_connection()  
    return db  # 错误:未yield导致资源未释放

# 错误2:中间件导入错误(如用flask的CORS而非fastapi的)
from flask import Flask
from fastapi import FastAPI

app = FastAPI()
app.add_middleware(Flask.middleware.cors.CORS)  # 导入错误

原因:依赖注入需用yield处理资源释放,中间件需导入FastAPI的对应模块。
正确代码

from fastapi import Depends, FastAPI
from contextlib import asynccontextmanager

# 正确:依赖注入用yield释放资源
@asynccontextmanager
async def get_db():  
    db = create_connection()  
    try:  
        yield db  
    finally:  
        db.close()  # 资源释放

@app.get("/items")
async def get_items(db=Depends(get_db)):  
    return db.query("SELECT * FROM items")  

解决方法
- 异步依赖用@asynccontextmanager标记,同步依赖用yieldasync def
- 中间件导入FastAPI自带模块(如CORSMiddleware而非Flask的)。

8. 文档访问问题

错误场景:Swagger UI或ReDoc无法访问(如路由未注册)。
错误代码

from fastapi import APIRouter

router = APIRouter()  # 未添加到app
@app.get("/items")
async def get_items():  
    return [1, 2, 3]  

原因:FastAPI自动生成文档需路由被注册到应用实例。
正确代码

from fastapi import FastAPI, APIRouter

app = FastAPI()
router = APIRouter()  # 路由定义

@router.get("/items")
async def get_items():  
    return [1, 2, 3]  

app.include_router(router)  # 注册路由到app

@app.get("/users")  # 直接装饰的路由也会生成文档
async def get_users():  
    return ["user1", "user2"]  

解决方法
- 路由用@app.get直接装饰或通过APIRouter.include_router注册。
- 启动服务后访问http://localhost:8000/docs查看Swagger UI。

总结

FastAPI的错误多源于“参数解析”“类型匹配”和“REST规范”的疏忽。新手可通过以下方式避免:
1. 优先参考官方文档(https://fastapi.tiangolo.com)和示例代码。
2. 开发时先写简单功能验证逻辑(如路径参数、状态码)。
3. 遇到问题检查:参数类型声明、请求体/查询参数使用、状态码是否符合REST规范。

随着实践增多,这些“坑”会逐渐转化为经验,让你的API开发更高效!

小夜