---
title: "用 Cloudflare 加速 AI 应用：缓存、API 限速与回源保护怎么配"
description: "用 Cloudflare 加速 AI 应用时，哪些内容能缓存，API 限速和防刷怎么做，源站怎样只接受边缘流量，SSE 流式输出为什么会被缓冲或出现 524 超时。附 Workers 代码和上线检查表。"
url: https://cdnping.org/blog/cloudflare-edge-for-ai-apps
language: zh-CN
published: 2026-10-17
category: "边缘与 CDN"
tags: ["Cloudflare","CDN","Workers","API 限速","SSE","回源保护"]
source: cdnping.org
license: Free to quote and summarize with a link to the url above.
---
# 用 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 绑定可以直接做到：

```toml
# 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 次，示例值
```

```js
// 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 秒发一次心跳：

```text
: ping

```

以冒号开头的行是 SSE 注释，标准的客户端会忽略。确实需要超过上限的非流式长任务，改成"提交任务 + 轮询结果"或用队列处理，不要指望延长超时。

### 3. 客户端断开后上游还在跑

用户关掉页面，边缘连接断开，但源站对上游模型的请求可能继续生成并计费。源站要监听连接关闭事件并取消上游请求（例如在 Node.js 里把 `AbortController` 的 signal 传给上游 fetch，在请求的 close 事件里调用 abort）。

## 上线前检查表

接入后用下面的命令逐项确认，几分钟就能跑完：

```bash
# 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](/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](/status/agiplan) 看它的探测和公开可用率。

另一个现实问题是中国大陆的访问。Cloudflare 的国际网络对大陆用户的延迟因运营商和地区差别很大；在大陆境内使用节点加速需要 ICP 备案，并经由持证服务商接入。接入前可以先用 cdnping 的[在线测速](/)看自己网络到各家 CDN 和 API 的首次连接与往返耗时，再参考 [CDN 速度榜](/benchmark/cdn)、[国内如何选择公共 CDN](/learn/choose-public-cdn-china) 和 [国内调用 AI API 的延迟](/learn/ai-api-latency-china)。

## 下一步

- 按第一节的表格，把你的路由逐条归类，写出两条缓存规则。
- 给对话接口加一条 WAF 限速规则，再用上面的 Worker 按 key 限速。
- 跑一遍检查表，重点看流式输出和直连源站这两项。
- 如果不想自己维护这套配置，[cdnping Edge](/edge) 提供基于 Cloudflare 全球网络的边缘加速服务，按需报价，提交邮箱后 1 个工作日内联系；涉及大陆境内加速的部分同样需要备案。
