這篇文章將教你如何在 FastAPI 中正確攔截並處理錯誤,確保 API 在遇到異常時回傳標準化的 HTTP 狀態碼 (Status Code) 與清晰的錯誤訊息,避免程式無預警崩潰,並讓前端開發者能根據狀態碼精準判斷錯誤類型。
什麼是錯誤處理?
錯誤處理是指當 API 接收到無法處理的請求或發生內部問題時,主動中斷執行流程並回傳特定格式回應的機制。這就像自動販賣機在存貨不足時會顯示「售完」燈號並退幣,而不是直接吞錢當機。這能讓前端開發者明確知道發生了什麼問題(如權限不足、資源不存在),並據此顯示對應的 UI 提示。
錯誤處理基礎概念
1. 使用 HTTPException
這是 FastAPI 中最基本的錯誤拋出方式,當你raise 這個異常時,FastAPI 會自動終止請求並回傳指定的 HTTP 回應。from fastapi import FastAPI, HTTPException, status
app = FastAPI()
items = {"a": "Food","b": "3C"}
@app.get("/items/{item_id}")
async def read_item(item_id: str):
if item_id not in items:
# 當找不到項目時,中斷執行並回傳 404
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
return {"item": items[item_id]}
這段程式碼會檢查 item_id 是否存在,若不存在則直接拋出 HTTP 404 錯誤,客戶端會收到 JSON 格式的錯誤訊息。
2. 使用 status 常數
為了避免在程式碼中使用 Magic Numbers (例如 404、500),FastAPI 提供了 status 模組。使用具名的常數能提升程式碼的可讀性與維護性。
from fastapi import FastAPI, HTTPException, status
app = FastAPI()
@app.get("/users/{identity}")
async def read_user(identity: str):
if identity == "admin":
raise HTTPException(
# 使用 status.HTTP_403_FORBIDDEN 代替數字 403
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin access is restricted"
)
return {"identity": identity}
使用 status.HTTP_403_FORBIDDEN 能讓開發者能直觀知道這是權限相關的錯誤,不需要查閱 HTTP 狀態碼對照表。
實作範例
以下範例模擬一個簡單的商品庫存系統。我們會根據不同的業務邏輯錯誤(找不到商品、庫存不足),回傳不同的 HTTP 狀態碼與錯誤訊息。
from fastapi import FastAPI, HTTPException, status
app = FastAPI()
# 模擬資料庫
inventory = {
"apple": {"name": "Apple", "quantity": 10},
"banana": {"name": "Banana", "quantity": 0}
}
@app.get("/buy/{item_name}/{count}")
async def buy_item(item_name: str, count: int):
# 步驟 1: 檢查商品是否存在
if item_name not in inventory:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"商品'{item_name}'不存在."
)
item = inventory[item_name]
# 步驟 2: 檢查購買數量是否合法
if count <= 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="購買數量必須大於0."
)
# 步驟 3: 檢查庫存是否足夠
if item["quantity"] < count:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=f"庫存數量不足,僅剩 {item['quantity']} 件."
)
# 扣除庫存並回傳成功訊息
item["quantity"] -= count
return {"message": f"成功購買了 {count} {item['name']}(個)", "remaining": item["quantity"]}
在此範例中,首先驗證商品是否存在,若無則回傳 404 (Not Found)。接著驗證請求數量是否大於 0,若否則回傳 400 (Bad Request),表示請求參數有誤。最後檢查庫存,若不足則回傳 409 (Conflict),表示資源狀態與請求衝突。每個錯誤情境都精準對應了合適的 HTTP 狀態碼。
常見錯誤與解決方法
1. 錯誤地使用 return 而非 raise
剛開始常誤以為要 return 一個錯誤物件,導致 FastAPI 把它當作正常回應處理,回傳 HTTP 200 OK,這會誤導前端判斷。
# 錯誤寫法:使用 return,狀態碼會變成 200 OK
if item_id not in items:
return {"error": "Item not found"}
# 正確寫法:使用 raise 中斷請求,狀態碼正確為 404
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
2. 使用不明確的狀態碼
雖然 HTTP 協定允許自定義狀態碼,但在標準 API 開發中,應該要盡量使用標準 HTTP 狀態碼。
# 錯誤寫法:全部錯誤都回傳 500 或自定義怪異數字
raise HTTPException(status_code=500, detail="User input error")
# 正確寫法:根據錯誤類型選擇語意正確的代碼 (如 400 參數錯誤)
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid user input")
結語
有效的錯誤處理是建構良好 API 的關鍵,請記住這三個重點:善用 raise HTTPException 來中斷異常流程、使用 status 來保持程式碼可讀性、並根據業務情境選擇最精確的 HTTP 狀態碼,這能讓你的 API 對接更順利,除錯更輕鬆。












