用 Cloudflare 加速 AI 應用:快取、API 限速與回源保護怎麼配

部落格 / 邊緣與 CDN

用 Cloudflare 加速 AI 應用:快取、API 限速與回源保護怎麼配

用 Cloudflare 加速 AI 應用,實際能拿到的是這些:靜態資源和少量只讀介面在邊緣快取,聊天介面在到達源站之前先被限速,源站 IP 不再直接暴露。流式輸出則要多處理一步:對話介面必須繞過快取,響應頭要儘早發出,長時間無輸出時要發心跳,否則容易遇到 524 超時或"一次性吐出全部內容"的假流式。下面按快取、限速、回源保護、SSE 的順序給出可以照做的配置。

AI 應用哪些介面能快取,哪些不能

AI 應用的流量可以按下表歸類,處理方式各不相同。Cloudflare 預設只快取按副檔名識別的靜態檔案,HTML 和 JSON 介面預設不快取,所以"能快取的介面"需要你主動用快取規則(Cache Rules)開啟,"不能快取的介面"則要確保沒有被誤開。

型別例子建議說明
靜態資源JS、CSS、字型、圖片、前端構建產物長快取,檔名帶雜湊邊緣 TTL 可設很長,發版靠改檔名
公共只讀介面模型列表、價格表、公開配置、文件頁短快取,幾十秒到幾分鐘前提是所有使用者看到的內容相同
按使用者區分的只讀介面當前使用者的額度、會話列表不快取,或在 Worker 裡把使用者標識放進快取鍵快取鍵漏掉使用者維度會把 A 的資料給 B
生成類介面對話、補全、Embedding、圖片生成不快取每次請求不同,且多為 POST 和流式
鑑權與計費登入、回撥、支付通知不快取,不改寫只做限速和來源校驗

判斷一個介面能不能快取,問自己兩個問題:響應是否只取決於 URL;同一個 URL 給任何人看都沒問題。兩個答案都是"是"才快取。模型列表介面要特別留意:如果它會按 API Key 返回不同的可用模型,就屬於表中“按使用者區分的只讀介面”。

快取規則示例

在 Cloudflare 控制檯的 Caching → Cache Rules 裡建兩條規則,順序如下:

  1. 生成類介面繞過快取 表示式:starts_with(http.request.uri.path, "/v1/chat") or starts_with(http.request.uri.path, "/v1/completions") or starts_with(http.request.uri.path, "/api/stream") 動作:Bypass cache。
  2. 公共只讀介面短快取 表示式:http.request.method eq "GET" and http.request.uri.path in {"/v1/models" "/api/pricing"} 動作:Eligible for cache;Edge TTL 設為 60 秒,忽略源站的 Cache-Control。

路徑按你自己的應用改。第一條雖然看起來多餘(POST 本來就不會被快取),但寫明之後,日後有人加"快取所有 /api"的規則時不容易誤傷。

API 限速怎麼做:邊緣按 IP,Worker 按使用者

AI 介面的單次成本遠高於普通介面,被刷的後果是賬單而不是頻寬。限速建議分兩層:邊緣按 IP 粗擋,Worker 或源站按使用者精擋。

第一層:WAF 限速規則

在 Security → WAF → Rate limiting rules 裡新建規則,例如:

  • 匹配:http.request.method eq "POST" and starts_with(http.request.uri.path, "/v1/chat")
  • 計數維度:IP
  • 閾值:假設每 10 秒 20 次(示例值,按你的真實使用調整)
  • 動作:Block 或 Managed Challenge,持續一段時間

瀏覽器端呼叫的介面可以用 Managed Challenge;給 SDK 或命令列工具用的介面不要用 Challenge,指令碼無法完成質詢,只會得到一堆 403,應直接返回 429。可用的計數維度、時間視窗和規則數量與套餐有關,以 Cloudflare 官方文件為準。

第二層:Worker 按使用者限速

按 IP 限速擋不住"一個賬號換很多 IP",也會誤傷公司、學校這類共用出口的使用者。按 API Key 或使用者 ID 限速更準確。Workers 的 Rate Limiting 繫結可以直接做到:

# wrangler.toml
name = "ai-edge"
main = "src/index.js"
compatibility_date = "2026-10-01"

[[ratelimits]]
name = "USER_LIMITER"
namespace_id = "1001"
simple = { limit = 30, period = 60 }  # 每個 key 每 60 秒 30 次,示例值
// src/index.js
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    if (url.pathname.startsWith("/v1/chat")) {
      const auth = request.headers.get("Authorization") || "";
      if (!auth) return new Response("missing key", { status: 401 });

      // 用 key 的雜湊做限速鍵,避免明文 key 出現在日誌裡
      const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(auth));
      const key = btoa(String.fromCharCode(...new Uint8Array(digest))).slice(0, 24);

      const { success } = await env.USER_LIMITER.limit({ key });
      if (!success) {
        return new Response(JSON.stringify({ error: "rate_limited" }), {
          status: 429,
          headers: { "Content-Type": "application/json", "Retry-After": "60" },
        });
      }
    }

    // 轉發到源站,並帶上只有邊緣知道的共享金鑰
    const upstream = new Request(request);
    upstream.headers.set("X-Edge-Secret", env.EDGE_SECRET);
    const resp = await fetch(upstream);

    // 直接把 body 流交回去,不要 await resp.text(),否則流式會變成一次性返回
    return new Response(resp.body, resp);
  },
};

這個繫結的計數是"按邊緣位置近似"的,適合擋濫用,不適合做精確計費。額度、餘額這類要求準確的限制,仍然放在源站或資料庫裡做。EDGE_SECRET 用 wrangler secret put EDGE_SECRET 寫入,不要寫進程式碼倉庫。

註冊和免費試用入口還可以加 Turnstile 人機驗證,配合郵箱驗證,比單純的 IP 限速更能擋住批次註冊。

怎樣讓源站只接受 Cloudflare 的流量

只把域名接入 Cloudflare 而不收緊源站,攻擊者找到源站 IP 後可以繞過所有邊緣規則直接打。下面幾種做法可以組合使用,按實施成本從低到高排列:

方式做法能防住什麼
共享金鑰頭Worker 或 Transform Rule 加 X-Edge-Secret,源站校驗直連源站的請求被拒(金鑰需定期輪換)
IP 白名單源站防火牆只放行 Cloudflare 公佈的 IP 段(cloudflare.com/ips)非 Cloudflare 來源的連線
Authenticated Origin Pulls源站要求 Cloudflare 出示客戶端證書(mTLS)非 Cloudflare 來源的連線;換成你自己上傳的證書後,還能擋住別人用自己的 Cloudflare 賬號把流量指向你的源站
Cloudflare Tunnel源站主動向外建隧道,不開放任何入站埠源站完全不暴露公網 IP

IP 白名單有一個常被忽略的漏洞:任何 Cloudflare 使用者的流量都來自同一批 IP 段,所以白名單最好與共享金鑰或 mTLS 一起用。另外,源站換 IP 前先查一下歷史 DNS 記錄和郵件頭裡是否洩露過舊 IP,舊 IP 洩露後單靠接入 Cloudflare 起不到隱藏作用。

SSE 流式輸出為什麼會卡住或超時

經過 Cloudflare 代理後,流式對話常見的問題有三個。

1. 被緩衝,變成一次性返回

Cloudflare 代理對 text/event-stream 會邊收邊轉,問題通常出在鏈路的其他環節:

  • 源站前面的 Nginx 預設會緩衝上游響應。在對應 location 里加 proxy_buffering off;,或讓應用返回 X-Accel-Buffering: no 響應頭。
  • 應用框架的壓縮中介軟體可能等攢夠資料才輸出,流式路由上關掉壓縮。
  • 響應頭建議帶上 Content-Type: text/event-stream、Cache-Control: no-cache, no-transform。
  • Worker 裡如果讀取了整個 body(await resp.text()、resp.json())再返回,流式同樣會失效。要改寫內容,用 TransformStream 逐塊處理。

2. 524 超時

Cloudflare 等待源站返回響應的時間有上限,免費和多數付費套餐是 100 秒(以官方文件為準),超時後返回 524。對 AI 應用來說,風險點在"首個 token 出來之前":長上下文、推理時間長的請求可能遲遲不發任何資料。做法是收到請求後立刻返回 200 和響應頭,然後先發一個 SSE 註釋行,之後每 15~30 秒發一次心跳:

: ping

以冒號開頭的行是 SSE 註釋,標準的客戶端會忽略。確實需要超過上限的非流式長任務,改成"提交任務 + 輪詢結果"或用佇列處理,不要指望延長超時。

3. 客戶端斷開後上遊還在跑

使用者關掉頁面,邊緣連線斷開,但源站對上游模型的請求可能繼續生成並計費。源站要監聽連線關閉事件並取消上游請求(例如在 Node.js 裡把 AbortController 的 signal 傳給上游 fetch,在請求的 close 事件裡呼叫 abort)。

上線前檢查表

接入後用下面的命令逐項確認,幾分鐘就能跑完:

# 1. 靜態資源是否命中快取(第二次請求應看到 cf-cache-status: HIT)
curl -sI https://your.app/assets/app.3f9c1a.js | grep -i cf-cache-status

# 2. 對話介面是否繞過快取(應為 BYPASS 或 DYNAMIC,不應出現 HIT)
curl -sI -X POST https://your.app/v1/chat -H "Authorization: Bearer test" | grep -i cf-cache-status

# 3. 流式是否逐塊到達(-N 關閉 curl 自身緩衝,輸出應一行行出現)
curl -N https://your.app/v1/chat -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" -d '{"stream":true,"messages":[{"role":"user","content":"數到 20"}]}'

# 4. 限速是否生效(連續請求,後面應出現 429)
for i in $(seq 1 40); do curl -s -o /dev/null -w "%{http_code}\n" -X POST https://your.app/v1/chat -H "Authorization: Bearer test"; done | sort | uniq -c

# 5. 源站是否拒絕直連(應超時、403 或連線被拒)
curl -sI --resolve your.app:443:<源站IP> https://your.app/
檢查項預期結果
帶雜湊的靜態檔案第二次請求 HIT
模型列表等公共介面HIT,且 TTL 到期後能重新整理
對話、補全介面從不出現 HIT
流式輸出逐塊出現,長請求不出 524
超出限速返回 429 並帶 Retry-After
直連源站 IP被拒絕

Cloudflare 加速管不到哪一段

邊緣只能最佳化"使用者到邊緣"和"邊緣到你的源站",源站再去呼叫模型 API 的那一段仍然取決於源站位置。作為參考,cdnping 在 2026 年 10 月 17 日(UTC)從 Cloudflare 丹佛(DEN)節點對各官方 API 入口做的探測(每 5 分鐘一次,當天視窗約 85 分鐘,來源 /status)中,api.anthropic.com 的中位數為 73 ms,api.openai.com 為 96 ms,而 api.deepseek.com 為 353 ms、open.bigmodel.cn 為 395 ms。資料視窗很短,只能說明一個方向:源站離哪家上游更近,就該部署在哪邊,邊緣層不能替代這個選擇。如果你的源站呼叫的是聚合閘道器,例如 AGI Plan(AGI Plan 是 cdnping 的商業合作方),可以在 /status/agiplan 看它的探測和公開可用率。

另一個現實問題是中國大陸的訪問。Cloudflare 的國際網路對大陸使用者的延遲因運營商和地區差別很大;在大陸境內使用節點加速需要 ICP 備案,並經由持證服務商接入。接入前可以先用 cdnping 的線上測速看自己網路到各家 CDN 和 API 的首次連線與往返耗時,再參考 CDN 速度榜、國內如何選擇公共 CDN 和 國內呼叫 AI API 的延遲。

下一步

  • 按第一節的表格,把你的路由逐條歸類,寫出兩條快取規則。
  • 給對話介面加一條 WAF 限速規則,再用上面的 Worker 按 key 限速。
  • 跑一遍檢查表,重點看流式輸出和直連源站這兩項。
  • 如果不想自己維護這套配置,cdnping Edge 提供基於 Cloudflare 全球網路的邊緣加速服務,按需報價,提交郵箱後 1 個工作日內聯絡;涉及大陸境內加速的部分同樣需要備案。

相關文章

繼續閱讀