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
解決方法:
- 優先使用異步依賴庫(如asyncpg、httpx.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標記,同步依賴用yield或async 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開發更高效!