用 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 裡建兩條規則,順序如下:
- 生成類介面繞過快取
表示式:
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。 - 公共只讀介面短快取
表示式:
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 個工作日內聯絡;涉及大陸境內加速的部分同樣需要備案。