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開發更高效!

小夜