FastAPI中間件:處理跨域、認證等請求攔截¶
在Web開發中,我們經常需要在請求到達後端處理邏輯之前,對請求進行統一檢查或處理。比如,判斷用戶是否有權限訪問API、處理前端跨域請求等。FastAPI的中間件(Middleware) 就是用來實現這類功能的“攔截器”——它可以在請求進入應用和響應返回之前,對請求數據進行修改、驗證或直接返回響應,讓我們能更靈活地控制請求的生命週期。
一、中間件是什麼?¶
簡單來說,中間件是一個函數,它會在請求到達路由函數之前(進入應用)和響應返回給客戶端之前(離開應用)被調用。你可以把它想象成一條“檢查線”:所有請求必須先通過這條線的檢查,才能繼續處理;響應返回前,也可以通過這條線做最後的調整。
每個中間件都有兩個核心作用:
1. 處理請求:在請求到達路由前,對請求數據進行驗證、修改或攔截。
2. 處理響應:在響應返回前,對響應數據進行統一處理(比如添加CORS頭、修改狀態碼等)。
中間件的執行順序非常重要:先註冊的中間件會先執行,返回時則相反(後註冊的先執行)。
二、處理跨域請求(CORS)¶
當你的前端頁面(比如http://localhost:3000)需要調用後端API(比如http://localhost:8000)時,瀏覽器會因爲“同源策略”阻止跨域請求(不同源:協議、域名、端口任意一個不同)。這時候就需要後端配置跨域資源共享(CORS),允許指定的前端源訪問API。
1. 安裝與配置CORS中間件¶
FastAPI通過CORSMiddleware處理CORS,需要先安裝fastapi和uvicorn(如果還沒裝):
pip install fastapi uvicorn
然後在代碼中導入並配置中間件:
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
app = FastAPI()
# 配置CORS中間件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允許的前端源,"*"表示所有源(開發環境用,生產環境建議指定具體域名)
allow_credentials=True, # 是否允許攜帶Cookie
allow_methods=["*"], # 允許的HTTP方法(GET/POST等),"*"表示所有方法
allow_headers=["*"], # 允許的請求頭,"*"表示所有頭信息
)
# 測試路由
@app.get("/api/hello")
async def hello():
return {"message": "Hello, Cross-Origin!"}
2. 關鍵參數說明¶
allow_origins:允許的前端域名列表,生產環境必須寫具體域名(如["https://your-frontend.com"]),避免安全風險。allow_methods:允許的HTTP方法(如["GET", "POST"]),不建議用"*"。allow_headers:允許的請求頭(如["Authorization"]),如果前端需要傳遞自定義頭(如Token),需在此列出。
三、認證攔截:驗證用戶身份¶
很多API需要驗證用戶身份(比如檢查Token),中間件可以在所有請求到達路由前統一攔截,驗證用戶是否有權限訪問。如果驗證失敗,直接返回“未授權”(401)錯誤,阻止請求進入路由函數。
1. 依賴項 vs 中間件¶
- 依賴項:更靈活,針對特定路由或函數,需要顯式聲明在路由參數中。
- 中間件:全局生效,無需在每個路由聲明,適合通用邏輯(如所有API都需要的認證檢查)。
這裏用中間件實現全局Token驗證:
from fastapi import Depends, Request, HTTPException
from fastapi.security import OAuth2PasswordBearer
# 模擬Token驗證邏輯(實際項目中需用JWT等真實驗證)
def verify_token(token: str) -> bool:
"""驗證Token是否有效(示例:簡單檢查Token是否爲"valid_token")"""
return token == "valid_token"
# OAuth2密碼流,獲取請求頭中的Token(前端通常放在Authorization: Bearer {token})
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# 定義認證中間件
class AuthMiddleware:
async def __call__(self, request: Request, call_next):
# 1. 獲取請求頭中的Token
token = request.headers.get("Authorization")
if not token or not token.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Token不存在或格式錯誤")
# 2. 提取Token內容(去除"Bearer "前綴)
token = token.split(" ")[1]
# 3. 驗證Token
if not verify_token(token):
raise HTTPException(status_code=401, detail="Token無效或已過期")
# 4. Token驗證通過,繼續執行下一個中間件或路由函數
response = await call_next(request)
return response
# 將中間件添加到FastAPI應用
app.add_middleware(AuthMiddleware)
# 測試路由(只有攜帶有效Token才能訪問)
@app.get("/api/protected")
async def protected_route():
return {"message": "這是需要認證的API!"}
2. 如何測試?¶
啓動服務後,用curl或Postman測試:
# 攜帶有效Token(Token爲"valid_token")
curl -H "Authorization: Bearer valid_token" http://localhost:8000/api/protected
# 無效Token(返回401)
curl -H "Authorization: Bearer invalid_token" http://localhost:8000/api/protected
四、中間件的注意事項¶
- 執行順序:多箇中間件按註冊順序執行,返回時逆序。例如:
app.add_middleware(Middleware1)
app.add_middleware(Middleware2)
請求會先經過Middleware1,再Middleware2,最後到路由;返回時先經過Middleware2,再Middleware1。
-
避免過度攔截:中間件邏輯要簡潔,避免複雜計算或數據庫操作,否則會影響性能。
-
區分場景:通用邏輯(如CORS、全局認證)用中間件;局部邏輯(如特定路由的權限)用依賴項。
總結¶
中間件是FastAPI中處理請求攔截的“瑞士軍刀”,能幫我們實現跨域處理、全局認證、日誌記錄等功能。通過CORSMiddleware解決前端跨域問題,通過自定義中間件實現全局認證,讓API開發更高效、安全。
小技巧:開發時先用allow_origins=["*"]快速調試跨域,生產環境務必替換爲具體域名;認證中間件要優先處理Token驗證,確保邏輯清晰、錯誤提示明確。
現在,你可以嘗試在自己的FastAPI項目中添加中間件,讓API更健壯吧!