本文 AI 產出,尚未審核

FastAPI

單元:中介層(Middleware)

主題:HTTPSRedirect Middleware


簡介

在現代 Web 應用程式中,HTTPS 已成為基本安全需求**,它不僅能防止資料在傳輸過程中被竊聽或竄改,還能提升搜尋引擎排名與使用者信任**。然而,許多開發者在部署 FastAPI 時,往往只在伺服器層面(例如 Nginx、Apache)設定 SSL,卻忽略了應用程式本身的「自動轉向」機制。

FastAPI 內建的 HTTPSRedirectMiddleware 正是為了在 HTTP 請求自動跳轉至 HTTPS 而設計的輕量級中介層。只要在程式碼中加入一行,即可確保所有進入的 HTTP 請求被正確導向到安全的 HTTPS 端點,減少因手動設定遺漏而產生的安全漏洞。

本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,帶你完整掌握 HTTPSRedirectMiddleware 的使用方式,讓你的 FastAPI 專案在 安全性與可維護性 兩方面都更上一層樓。


核心概念

什麼是 Middleware?

在 FastAPI(以及底層的 Starlette)中,Middleware 是一段位於請求(Request)與回應(Response)之間的程式碼,負責攔截、修改或記錄 HTTP 流量。它的執行順序遵循「先註冊的先執行」的原則,且每個 Middleware 必須呼叫 await call_next(request) 才能將控制權交給下游的處理流程。

HTTPSRedirectMiddleware 繼承自 Starlette 的 BaseHTTPMiddleware,其核心邏輯非常簡單:

  1. 檢查 request.url.scheme 是否為 "http"
  2. 若是,產生一個 301(永久)或 307(暫時) 的重新導向回應,目標 URL 為相同的主機與路徑,但使用 https
  3. 若不是,直接把請求傳遞給下游的路由或其他 Middleware。

重點:此 Middleware 只負責「協議層」的轉向,不會處理 證書驗證HSTS(HTTP Strict Transport Security)等其他安全機制——這些仍需自行在伺服器或額外 Middleware 中設定。

為什麼要在程式碼層面加上 HTTPS 轉向?

  • 防止遺漏:即使在反向代理(Reverse Proxy)上已設定 SSL,若使用者直接以 HTTP 請求到達 FastAPI(例如在本機測試),仍可能收到未加密的回應。
  • 一致性:在多個環境(開發、測試、正式)中,僅透過環境變數切換即可開關轉向,避免在不同環境手動調整 Nginx 設定。
  • 支援自訂域名與子路徑HTTPSRedirectMiddleware 會自動保留原始的 hostportpathquery string,確保使用者不會因為轉向而失去原本的網址資訊。

程式碼範例

以下示範 5 個實用的範例,從最簡單的套用到進階的自訂行為,都以 Python 為例(使用 python 標記)。

1️⃣ 基本使用:直接套用 Middleware

from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

app = FastAPI()

# 只要在開發或測試環境不需要,正式環境直接掛上即可
app.add_middleware(HTTPSRedirectMiddleware)

@app.get("/")
def read_root():
    return {"message": "Hello, HTTPS!"}

說明:只要有 HTTP 請求進來,FastAPI 會自動回傳 307 Temporary Redirect,指向相同的 URL 但使用 https

2️⃣ 設定 永久轉向 (301)

HTTPSRedirectMiddleware 預設使用 307,若想改為 301(搜尋引擎友好),可以自行繼承或使用 RedirectResponse

from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

class PermanentHTTPSRedirectMiddleware(HTTPSRedirectMiddleware):
    async def dispatch(self, request: Request, call_next):
        if request.url.scheme == "http":
            url = request.url.replace(scheme="https")
            return RedirectResponse(url=str(url), status_code=301)
        return await call_next(request)

app = FastAPI()
app.add_middleware(PermanentHTTPSRedirectMiddleware)

說明:繼承後只改變回應的 status_code,其他行為保持不變。

3️⃣ 在 開發環境 暫時關閉轉向

開發時常使用 http://127.0.0.1:8000,若強制轉向會導致瀏覽器頻繁出現安全警告。以下示範如何根據環境變數自動開關:

import os
from fastapi import FastAPI
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

app = FastAPI()

if os.getenv("ENVIRONMENT") == "production":
    app.add_middleware(HTTPSRedirectMiddleware)   # 只在正式環境啟用

@app.get("/info")
def get_info():
    return {"env": os.getenv("ENVIRONMENT", "development")}

技巧:在 docker-compose.yml 或 CI/CD pipeline 中設定 ENVIRONMENT=production,即可無痛切換。

4️⃣ 反向代理(如 Nginx)下的特殊處理

當 FastAPI 後面有 Nginx 代理,且 Nginx 已將 HTTPS 終止,FastAPI 收到的仍是 http。此時需要透過 X-Forwarded-Proto 標頭告訴 Middleware 真實協議:

from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware

class ProxyHeadersHTTPSRedirectMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # 依據 X-Forwarded-Proto 判斷原始協議
        forwarded_proto = request.headers.get("x-forwarded-proto")
        scheme = forwarded_proto or request.url.scheme
        if scheme == "http":
            url = request.url.replace(scheme="https")
            return RedirectResponse(url=str(url), status_code=307)
        return await call_next(request)

app = FastAPI()
app.add_middleware(ProxyHeadersHTTPSRedirectMiddleware)

說明:在 Nginx 配置中加入 proxy_set_header X-Forwarded-Proto $scheme;,即可讓此 Middleware 正確辨識。

5️⃣ 與其他 Middleware 同時使用(順序示範)

如果你同時使用 CORSGZipHTTPSRedirect,必須注意加入的順序。以下示範正確的排列方式:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware

app = FastAPI()

# 1. 先處理跨域,讓瀏覽器在 HTTP 階段就能取得 CORS 回應
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

# 2. 再壓縮回應(不影響轉向)
app.add_middleware(GZipMiddleware, minimum_size=1000)

# 3. 最後放置 HTTPSRedirect,確保所有非安全請求被導向
app.add_middleware(HTTPSRedirectMiddleware)

@app.get("/data")
def get_data():
    return {"msg": "This response may be gzipped if large enough."}

重點HTTPSRedirectMiddleware 必須放在 最後,否則後續的壓縮或 CORS 可能在 HTTP 請求上被觸發,浪費資源。


常見陷阱與最佳實踐

陷阱 可能的後果 解決方案或最佳實踐
在開發環境未關閉 瀏覽器不斷跳回 HTTPS,導致 SSL 證書錯誤自簽證書 警告 使用環境變數或 if settings.debug: ... 只在正式環境啟用
與反向代理協議不一致 仍收到 HTTP 回應,使用者資料被明文傳輸 在 Nginx/Traefik 設定 X-Forwarded-Proto,並在 Middleware 讀取此標頭
重複加入 Middleware 出現 雙重 301/307 迴圈,最終導致瀏覽器「過多重新導向」錯誤 確認 app.add_middleware 只呼叫一次,或使用 app.middleware("http") 裝飾器取代
轉向前已產生回應 (如在 ExceptionMiddleware 前) 轉向無法執行,錯誤訊息仍以 HTTP 回傳 確保 HTTPSRedirectMiddleware 登記在 所有其他 Middleware 之前(即最外層)
忘記設定 HSTS 雖然已轉向 HTTPS,仍允許瀏覽器以 HTTP 請求連線,降低安全性 在 CDN 或 Nginx 中加入 Strict-Transport-Security 標頭;或自行寫 SecurityHeadersMiddleware 追加此標頭

最佳實踐清單

  1. 只在 Production 啟用:以 ENVIRONMENTDEBUGsettings.is_production 判斷。
  2. 配合 HSTS:在最外層加上 Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  3. 使用 301 永久轉向:對外部搜尋引擎友好,但在測試階段仍建議保留 307,避免快取問題。
  4. 保持 Middleware 執行順序HTTPSRedirectMiddleware 應是 最後 加入的 HTTP Middleware(除非有特殊需求)。
  5. 在 Docker / Kubernetes 中統一設定:將 ENVIRONMENT=production 放在容器的環境變數,避免忘記手動切換。

實際應用場景

1️⃣ SaaS 平台的多租戶服務

一個提供 SaaS 服務的公司,所有客戶都必須透過 HTTPS 交換機密資訊(帳號、付款資料)。即使客戶自行在防火牆或本機測試,仍可能誤以為未加密。透過在 FastAPI 專案中加入 HTTPSRedirectMiddleware,可以保證 所有入口(無論是 CDN、負載平衡器或直接 IP)都會自動導向安全通道,省去在每個子域名或客戶環境中個別設定的麻煩。

2️⃣ 微服務架構中的內部 API

在微服務叢集內部,部分服務仍使用 HTTP(因為在同一個 VPC 中被認為足夠安全),但對外的 API 必須使用 HTTPS。此時可以在 gateway / API 聚合層(如 FastAPI 作為 API Gateway)加入 HTTPSRedirectMiddleware,讓外部請求自動升級,而內部服務保持輕量的 HTTP 通訊。

3️⃣ IoT 裝置的遠端管理平台

許多 IoT 裝置僅支援 HTTP 直接連線,但管理平台必須確保管理者的操作是加密的。透過在 FastAPI 管理介面加上 HTTPSRedirectMiddleware,即使裝置端仍使用 HTTP,管理者的 Web UI 仍會被強制升級到 HTTPS,降低敏感指令被竊聽的風險。


總結

HTTPSRedirectMiddleware 是 FastAPI 提供的 零配置、即插即用 的安全防護機制,讓開發者能在程式碼層面確保所有 HTTP 請求自動導向 HTTPS。透過本文的五個實作範例,你可以:

  • 快速上手:只要一行 app.add_middleware(HTTPSRedirectMiddleware)
  • 自訂行為:如改用 301 永久轉向或依據 X-Forwarded-Proto 判斷。
  • 彈性開關:根據環境變數在開發與正式環境間切換。
  • 正確排序:與其他 Middleware(CORS、GZip、SecurityHeaders)協同工作。

在實務上,將 HTTPS 轉向納入程式碼,可以避免因部署環境差異產生的安全漏洞,同時減少在反向代理或負載平衡器上重複設定的工作量。結合 HSTS安全標頭 以及 適當的環境切換,即可打造一個 安全、可維護且易於部署 的 FastAPI 服務。

最後提醒:安全是一個多層防禦的概念,HTTPSRedirectMiddleware 只是第一層;請務必配合 SSL 證書、HSTS、CSP、Rate Limiting 等機制,才能提供完整的防護。祝開發順利,讓你的 API 在安全與效能上都能發光發熱!