FastAPI CORS 跨來源資源共用

CORS (Cross-Origin Resource Sharing) 是一種瀏覽器的安全機制。

當你的前端 (例如 Vue, React) 跑在 http://localhost:3000,而後端 FastAPI 跑在 http://localhost:8000 時,如果不設定 CORS,瀏覽器會攔截前端發出的請求,並顯示類似 Access-Control-Allow-Origin 的錯誤。

使用 CORSMiddleware

FastAPI 提供了 CORSMiddleware 來解決這個問題。

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

app = FastAPI()

# 允許的來源列表
origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
    "http://localhost:3000", # 常見的前端開發 Port
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,       # 允許的來源
    allow_credentials=True,      # 是否允許攜帶 Cookie 等憑證
    allow_methods=["*"],         # 允許的 HTTP 方法 (GET, POST, etc.),"*" 代表全部允許
    allow_headers=["*"],         # 允許的 HTTP Header,"*" 代表全部允許
)

@app.get("/")
async def main():
    return {"message": "Hello World"}

參數說明

  • allow_origins:一個允許的來源 URL 列表 (字串的 List)。例如 ['http://localhost:3000']。如果你想允許所有來源,可以使用 ['*']
  • allow_origin_regex:使用正規表達式來匹配允許的來源。
  • allow_credentials:布林值。設定為 True 代表允許瀏覽器在跨域請求中傳送 Cookie (例如用於 Session 登入)。注意:若設為 True,allow_origins 不能為 ['*'],必須明確指定來源。
  • allow_methods:允許的 HTTP 方法列表,如 ['GET', 'POST']。預設為 ['GET']。使用 ['*'] 代表允許所有。
  • allow_headers:允許的 HTTP Header 列表。預設為 []。使用 ['*'] 允許所有 Header (包括前端自訂的 Header)。

常見問題

為什麼使用了 ['*'] 還是報錯?

如果你設定了 allow_credentials=True,標準規定 allow_origins 不能是 ['*']。你必須明確列出所有允許的 Domain。

什麼是 Preflight Request (OPTIONS)?

對於某些「非簡單請求」(例如帶有自訂 Header 或 Content-Type 為 application/json 的 POST),瀏覽器會先發送一個 OPTIONS 請求來詢問伺服器是否允許。CORSMiddleware 會自動幫你處理這個 OPTIONS 請求並回傳正確的 Header。

總結

  • 只要是前後端分離開發,幾乎一定會遇到 CORS 問題。
  • 使用 CORSMiddleware 並正確設定 allow_origins 即可解決。
  • 開發環境可以開得比較寬鬆,生產環境請務必限制來源以保安全。