Use Cases (更新: 2026/6/3)

用 Claude Code 实战 Cloudflare Workers 边缘 API

用Claude Code实现Workers API:Wrangler、KV/D1/R2、缓存、限流、日志和安全响应头。

用 Claude Code 实战 Cloudflare Workers 边缘 API

Cloudflare Workers 可以把 JavaScript/TypeScript 运行在 Cloudflare 的边缘网络上。所谓边缘,就是尽量靠近用户的位置执行代码,而不是所有请求都回到单一区域。它适合轻量 API、Webhook、BFF、缓存响应、安全检查和文件下载控制。

Claude Code 适合这类工作,因为 Workers 项目通常由清晰的 fetch 入口、wrangler.toml 配置和显式 binding 组成。本文已在 2026 年 6 月 3 日复核官方文档;实现前建议打开 WorkersWranglerbindingsKVD1R2Cache APIRate LimitingWorkers Logs。内部延伸阅读可参考 serverless functionsAWS Lambda guide

本文要做什么

我们实现一个订单 API:D1 保存订单,KV 保存小配置,R2 保存收据 JSON,Cache API 缓存安全的 GET 响应,Rate Limiting 限制频率,Workers Logs 记录结构化日志,并为所有响应加安全头。

flowchart LR
  Client["客户端"] --> Worker["Worker fetch handler"]
  Worker --> D1["D1 订单表"]
  Worker --> KV["KV 设置"]
  Worker --> R2["R2 收据"]
  Worker --> Cache["Cache API"]
  Worker --> Logs["Workers Logs"]

binding 可以理解成“把外部能力注入 Worker 的变量”。例如 binding = "DB" 会让代码通过 env.DB 访问 D1。

给 Claude Code 的提示词

请用 Cloudflare Workers + TypeScript 实现订单 API。

文件:
- src/index.ts
- wrangler.toml
- schema.sql

要求:
- 使用 module fetch handler
- GET /health 返回 JSON
- GET /orders/:id 从 D1 读取,并只缓存安全公开输出 30 秒
- POST /orders 校验 JSON 后写入 D1
- 用 Authorization Bearer 和 API_TOKEN 校验
- 使用 SETTINGS KV、DB D1、RECEIPTS R2、API_RATE_LIMITER binding
- 每个响应都带 security headers
- console.log 输出 JSON 对象
- 提供 curl 验证命令

禁止:
- 把 secret 写进 wrangler.toml
- 假设有长期运行的 Node.js server
- 用伪代码代替实现

Wrangler 配置

npm create cloudflare@latest claude-worker-api -- --type=hello-world
cd claude-worker-api
npm install -D typescript wrangler
npx wrangler --version

C3 新项目可能生成 wrangler.jsonc。Wrangler 支持 JSON/JSONC 和 TOML 配置文件;本文为了可读性使用 TOML。如果你的项目已经使用 wrangler.jsonc,保持同样的 key,用 JSONC 写法即可。

name = "claude-worker-api"
main = "src/index.ts"
compatibility_date = "2026-06-03"

[vars]
PUBLIC_ENV = "production"

[observability]
enabled = true
head_sampling_rate = 1

[[d1_databases]]
binding = "DB"
database_name = "claude-worker-api"
database_id = "replace-with-d1-database-id"

[[kv_namespaces]]
binding = "SETTINGS"
id = "replace-with-kv-namespace-id"

[[r2_buckets]]
binding = "RECEIPTS"
bucket_name = "claude-worker-receipts"

[[ratelimits]]
name = "API_RATE_LIMITER"
namespace_id = "1001"

  [ratelimits.simple]
  limit = 60
  period = 60
npx wrangler login
npx wrangler d1 create claude-worker-api
npx wrangler kv namespace create SETTINGS
npx wrangler r2 bucket create claude-worker-receipts
npx wrangler secret put API_TOKEN

D1 表结构

CREATE TABLE IF NOT EXISTS orders (
  id TEXT PRIMARY KEY,
  email TEXT NOT NULL,
  amount INTEGER NOT NULL,
  status TEXT NOT NULL DEFAULT 'pending',
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX IF NOT EXISTS idx_orders_email ON orders(email);
npx wrangler d1 execute claude-worker-api --local --file=./schema.sql
npx wrangler d1 execute claude-worker-api --remote --file=./schema.sql

可运行的 src/index.ts

export interface Env {
  API_TOKEN: string;
  PUBLIC_ENV: string;
  DB: D1Database;
  SETTINGS: KVNamespace;
  RECEIPTS: R2Bucket;
  API_RATE_LIMITER: RateLimit;
}

const securityHeaders = {
  "content-security-policy": "default-src 'none'; frame-ancestors 'none'",
  "x-content-type-options": "nosniff",
  "x-frame-options": "DENY",
  "referrer-policy": "no-referrer",
  "permissions-policy": "camera=(), microphone=(), geolocation=()",
};

function json(data: unknown, init: ResponseInit = {}) {
  return new Response(JSON.stringify(data), {
    ...init,
    headers: {
      "content-type": "application/json; charset=utf-8",
      ...securityHeaders,
      ...init.headers,
    },
  });
}

export default {
  async fetch(request, env, ctx): Promise<Response> {
    const url = new URL(request.url);
    const requestId = crypto.randomUUID();
    console.log({ event: "request_started", requestId, method: request.method, path: url.pathname });

    if (url.pathname === "/health") {
      const maintenance = await env.SETTINGS.get("maintenance");
      return json({ ok: true, env: env.PUBLIC_ENV, maintenance: maintenance === "true" });
    }

    if (request.headers.get("authorization") !== `Bearer ${env.API_TOKEN}`) {
      return json({ error: "unauthorized" }, { status: 401 });
    }

    const { success } = await env.API_RATE_LIMITER.limit({
      key: request.headers.get("authorization")?.slice(-16) ?? "anonymous",
    });
    if (!success) return json({ error: "rate_limited" }, { status: 429 });

    const match = url.pathname.match(/^\/orders\/([a-zA-Z0-9_-]+)$/);

    if (request.method === "GET" && match) {
      const cacheKey = new Request(url.toString(), { method: "GET" });
      const cached = await caches.default.match(cacheKey);
      if (cached) return cached;

      const order = await env.DB.prepare(
        "SELECT id, email, amount, status, created_at FROM orders WHERE id = ?"
      ).bind(match[1]).first();
      if (!order) return json({ error: "not_found" }, { status: 404 });

      const response = json({ order }, {
        headers: { "cache-control": "public, max-age=30", "cache-tag": `order-${match[1]}` },
      });
      ctx.waitUntil(caches.default.put(cacheKey, response.clone()));
      return response;
    }

    if (request.method === "POST" && url.pathname === "/orders") {
      const body = await request.json<{ email?: string; amount?: number }>();
      if (!body.email?.includes("@") || !Number.isInteger(body.amount) || body.amount <= 0) {
        return json({ error: "invalid_order" }, { status: 400 });
      }

      const id = crypto.randomUUID();
      await env.DB.prepare(
        "INSERT INTO orders (id, email, amount, status) VALUES (?, ?, ?, ?)"
      ).bind(id, body.email, body.amount, "pending").run();

      await env.RECEIPTS.put(`orders/${id}.json`, JSON.stringify({ id, email: body.email, amount: body.amount }), {
        httpMetadata: { contentType: "application/json" },
      });

      console.log({ event: "order_created", requestId, orderId: id });
      return json({ id, status: "pending" }, { status: 201 });
    }

    return json({ error: "not_found" }, { status: 404 });
  },
} satisfies ExportedHandler<Env>;

本地验证与部署

printf "API_TOKEN=dev-token\n" > .dev.vars
npx wrangler dev
curl http://localhost:8787/health

curl -X POST http://localhost:8787/orders \
  -H "authorization: Bearer dev-token" \
  -H "content-type: application/json" \
  -d "{\"email\":\"masa@example.com\",\"amount\":1200}"

curl http://localhost:8787/orders/replace-with-created-id \
  -H "authorization: Bearer dev-token"
npx wrangler secret put API_TOKEN
npx wrangler d1 execute claude-worker-api --remote --file=./schema.sql
npx wrangler deploy
npx wrangler tail

真实使用场景

第一个场景是表单或订单 API。D1 存记录,R2 存附件或收据,日志保留排查线索。

第二个场景是 Webhook 接收端。验证签名,把事件 ID 存入 D1,重复事件直接跳过。

第三个场景是 BFF,也就是面向前端的轻量后端。Worker 隐藏上游 API key,整理响应格式,并缓存安全数据。

第四个场景是 R2 文件下载控制。大文件放 R2,授权、日志和响应头由 Worker 处理。

这些场景共同点是请求边界很清楚:收到请求、校验、读写少量资源、快速返回。让 Claude Code 处理这类任务时,不要只说“做一个后端”,而要说明每个 endpoint 的输入、输出、binding 和验证命令。这样生成的差分更容易 review,也更容易用 curl 复现。

如果任务变重,例如图片转码、PDF 生成、长时间 AI 推理、批量同步,就不要让 Worker 在一次请求里全部做完。更稳妥的做法是让 Worker 负责认证、排队、记录状态,再把慢任务交给 Cloud Run、Lambda、Queues 或其他后台服务。这个边界要在实现前就让 Claude Code 解释清楚。

常见坑

不要把 Workers 当成长期运行的 Node.js server。优先使用 Web API、RequestResponsefetchcrypto 和 binding。

不要混用存储职责。KV 放小配置,D1 放关系数据,R2 放对象文件,Cache API 做短期响应加速。

不要缓存私人响应。包含 cookie、token、邮箱或用户专属数据的响应,不应进入共享缓存。

不要只按 IP 限流。公司网络和移动网络会共享 IP,最好用 API key、user ID 或 tenant ID。

还要注意环境变量的边界。.dev.vars 适合本地开发,生产 secret 必须用 wrangler secret put 或 Cloudflare dashboard 管理。wrangler.toml 里的 vars 只能放公开配置,不要放 token、cookie secret 或 webhook secret。

日志也要按生产数据对待。Workers Logs 很适合排查问题,但如果把 Authorization header、cookie、完整请求体或客户邮箱直接打进去,后续就会变成可搜索的敏感数据。建议只记录 requestId、route、状态码、orderId 和粗粒度错误类型。

如何选择平台

低延迟 HTTP API、Cloudflare cache 和 bindings 优先选 Workers。Cloudflare Pages 站点旁边只需要少量动态逻辑时选 Pages Functions。需要容器、完整框架或长任务时选 Cloud Run。工作流围绕 AWS S3、DynamoDB、EventBridge、SQS 时选 Lambda。

Claude Code 审查提示词

请审查这个 Cloudflare Workers 实现。

检查:
- 是否兼容 Workers runtime
- Env 类型和 wrangler binding 名称是否一致
- secret 是否泄漏到代码、日志或配置
- D1 是否使用 bind,是否有 SQL injection 风险
- Cache API 是否缓存了不安全响应
- Rate Limiting key 是否合理
- 每个响应是否都有 security headers
- curl 验证步骤是否完整

按严重程度输出问题、修复建议和测试建议。

CTA 与实测记录

迁移时先选一个端点:/health、只读 GET 或 Webhook。把文件范围、binding 名、验证命令和禁止事项交给 Claude Code。可复用模板请看 products;团队培训和代码审查习惯请看 training

实际试用结果:本文示例按 Wrangler、D1、Worker、curl 的顺序串联检查过;上线前请在自己的 Cloudflare 账户里重新确认 wrangler deploywrangler tail、响应头、缓存命中和 429 行为。

#Claude Code #Cloudflare Workers #edge computing #serverless #API
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。