cloudflare-workers

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cloudflare Workers

Cloudflare Workers

Deploy JavaScript and TypeScript functions to Cloudflare's global edge network with sub-millisecond cold starts.
将JavaScript和TypeScript函数部署到Cloudflare全球边缘网络,冷启动时间低至亚毫秒级。

When to Use

适用场景

  • Building lightweight APIs and microservices at the edge.
  • Adding middleware (auth, rate limiting, header injection) in front of origin servers.
  • Running cron jobs on a schedule without maintaining infrastructure.
  • Processing webhooks, image transformations, or A/B testing logic.
  • Serving dynamic content from KV, D1, or R2 storage bindings.
  • 在边缘构建轻量级API和微服务。
  • 在源服务器前添加中间件(认证、限流、请求头注入)。
  • 无需维护基础设施,按计划运行定时任务。
  • 处理Webhook、图片转换或A/B测试逻辑。
  • 从KV、D1或R2存储绑定中提供动态内容。

Prerequisites

前置条件

  • Node.js 18+ installed locally.
  • Wrangler CLI:
    npm install -g wrangler
    .
  • Cloudflare account (free plan supports 100,000 requests/day).
  • Authenticated:
    wrangler login
    or set
    CLOUDFLARE_API_TOKEN
    .
  • 本地安装Node.js 18+版本。
  • Wrangler CLI:
    npm install -g wrangler
    .
  • Cloudflare账户(免费计划支持每日10万次请求)。
  • 完成认证:
    wrangler login
    或设置
    CLOUDFLARE_API_TOKEN

Quick Start

快速开始

bash
undefined
bash
undefined

Scaffold a new Worker project

Scaffold a new Worker project

npm create cloudflare@latest my-worker cd my-worker
npm create cloudflare@latest my-worker cd my-worker

Login to Cloudflare

Login to Cloudflare

npx wrangler login
npx wrangler login

Start local development server (port 8787)

Start local development server (port 8787)

npx wrangler dev
npx wrangler dev

Deploy to production

Deploy to production

npx wrangler deploy
undefined
npx wrangler deploy
undefined

Essential Wrangler Commands

Wrangler核心命令

bash
undefined
bash
undefined

Local development with remote bindings (KV, D1, R2)

Local development with remote bindings (KV, D1, R2)

npx wrangler dev --remote
npx wrangler dev --remote

Deploy to a specific environment

Deploy to a specific environment

npx wrangler deploy --env staging
npx wrangler deploy --env staging

Set a secret (prompts for value)

Set a secret (prompts for value)

npx wrangler secret put API_TOKEN npx wrangler secret put API_TOKEN --env staging
npx wrangler secret put API_TOKEN npx wrangler secret put API_TOKEN --env staging

List secrets

List secrets

npx wrangler secret list
npx wrangler secret list

Tail production logs in real time

Tail production logs in real time

npx wrangler tail
npx wrangler tail

Tail with filters

Tail with filters

npx wrangler tail --status=error --search="timeout"
npx wrangler tail --status=error --search="timeout"

View deployment versions

View deployment versions

npx wrangler deployments list
npx wrangler deployments list

Rollback to a previous deployment

Rollback to a previous deployment

npx wrangler rollback
undefined
npx wrangler rollback
undefined

Wrangler Configuration

Wrangler配置

toml
undefined
toml
undefined

wrangler.toml

wrangler.toml

name = "my-api" main = "src/index.ts" compatibility_date = "2024-09-01" compatibility_flags = ["nodejs_compat"]
name = "my-api" main = "src/index.ts" compatibility_date = "2024-09-01" compatibility_flags = ["nodejs_compat"]

Custom routes

Custom routes

routes = [ { pattern = "api.example.com/*", zone_name = "example.com" } ]
routes = [ { pattern = "api.example.com/*", zone_name = "example.com" } ]

Or use a workers.dev subdomain

Or use a workers.dev subdomain

workers_dev = true

workers_dev = true

Environment variables (non-secret)

Environment variables (non-secret)

[vars] ENVIRONMENT = "production" API_VERSION = "v2"
[vars] ENVIRONMENT = "production" API_VERSION = "v2"

Staging environment override

Staging environment override

[env.staging] name = "my-api-staging" routes = [ { pattern = "api-staging.example.com/*", zone_name = "example.com" } ] [env.staging.vars] ENVIRONMENT = "staging"
undefined
[env.staging] name = "my-api-staging" routes = [ { pattern = "api-staging.example.com/*", zone_name = "example.com" } ] [env.staging.vars] ENVIRONMENT = "staging"
undefined

Worker Examples

Worker示例

Basic API Router

基础API路由

typescript
// src/index.ts
export interface Env {
  ENVIRONMENT: string;
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);

    switch (url.pathname) {
      case "/":
        return new Response("OK", { status: 200 });

      case "/api/health":
        return Response.json({
          status: "healthy",
          env: env.ENVIRONMENT,
          timestamp: new Date().toISOString(),
        });

      case "/api/data":
        if (request.method !== "POST") {
          return new Response("Method Not Allowed", { status: 405 });
        }
        const body = await request.json();
        // Process in the background after returning response
        ctx.waitUntil(logToAnalytics(body));
        return Response.json({ received: true });

      default:
        return new Response("Not Found", { status: 404 });
    }
  },
};

async function logToAnalytics(data: unknown): Promise<void> {
  await fetch("https://analytics.example.com/ingest", {
    method: "POST",
    body: JSON.stringify(data),
    headers: { "Content-Type": "application/json" },
  });
}
typescript
// src/index.ts
export interface Env {
  ENVIRONMENT: string;
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);

    switch (url.pathname) {
      case "/":
        return new Response("OK", { status: 200 });

      case "/api/health":
        return Response.json({
          status: "healthy",
          env: env.ENVIRONMENT,
          timestamp: new Date().toISOString(),
        });

      case "/api/data":
        if (request.method !== "POST") {
          return new Response("Method Not Allowed", { status: 405 });
        }
        const body = await request.json();
        // Process in the background after returning response
        ctx.waitUntil(logToAnalytics(body));
        return Response.json({ received: true });

      default:
        return new Response("Not Found", { status: 404 });
    }
  },
};

async function logToAnalytics(data: unknown): Promise<void> {
  await fetch("https://analytics.example.com/ingest", {
    method: "POST",
    body: JSON.stringify(data),
    headers: { "Content-Type": "application/json" },
  });
}

Middleware: Rate Limiting with KV

中间件:基于KV的限流

typescript
// src/rate-limiter.ts
interface Env {
  RATE_LIMIT_KV: KVNamespace;
  ORIGIN_URL: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const ip = request.headers.get("CF-Connecting-IP") || "unknown";
    const key = `ratelimit:${ip}`;
    const window = 60; // seconds
    const maxRequests = 100;

    const current = parseInt((await env.RATE_LIMIT_KV.get(key)) || "0");

    if (current >= maxRequests) {
      return new Response("Too Many Requests", {
        status: 429,
        headers: { "Retry-After": String(window) },
      });
    }

    await env.RATE_LIMIT_KV.put(key, String(current + 1), {
      expirationTtl: window,
    });

    // Forward to origin
    const originRequest = new Request(env.ORIGIN_URL + new URL(request.url).pathname, request);
    return fetch(originRequest);
  },
};
typescript
// src/rate-limiter.ts
interface Env {
  RATE_LIMIT_KV: KVNamespace;
  ORIGIN_URL: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const ip = request.headers.get("CF-Connecting-IP") || "unknown";
    const key = `ratelimit:${ip}`;
    const window = 60; // seconds
    const maxRequests = 100;

    const current = parseInt((await env.RATE_LIMIT_KV.get(key)) || "0");

    if (current >= maxRequests) {
      return new Response("Too Many Requests", {
        status: 429,
        headers: { "Retry-After": String(window) },
      });
    }

    await env.RATE_LIMIT_KV.put(key, String(current + 1), {
      expirationTtl: window,
    });

    // Forward to origin
    const originRequest = new Request(env.ORIGIN_URL + new URL(request.url).pathname, request);
    return fetch(originRequest);
  },
};

KV Storage Binding

KV存储绑定

toml
undefined
toml
undefined

wrangler.toml

wrangler.toml

[[kv_namespaces]] binding = "MY_KV" id = "abc123def456"
[[kv_namespaces]] binding = "MY_KV" id = "abc123def456"

Preview namespace for local dev

Preview namespace for local dev

[[kv_namespaces]] binding = "MY_KV" id = "abc123def456" preview_id = "preview789"

```typescript
// KV operations in a Worker
interface Env {
  MY_KV: KVNamespace;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Write with TTL
    await env.MY_KV.put("session:abc", JSON.stringify({ user: "alice" }), {
      expirationTtl: 3600,
    });

    // Read
    const session = await env.MY_KV.get("session:abc", "json");

    // List keys by prefix
    const list = await env.MY_KV.list({ prefix: "session:", limit: 100 });

    // Delete
    await env.MY_KV.delete("session:abc");

    return Response.json({ session, keys: list.keys.length });
  },
};
bash
undefined
[[kv_namespaces]] binding = "MY_KV" id = "abc123def456" preview_id = "preview789"

```typescript
// KV operations in a Worker
interface Env {
  MY_KV: KVNamespace;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Write with TTL
    await env.MY_KV.put("session:abc", JSON.stringify({ user: "alice" }), {
      expirationTtl: 3600,
    });

    // Read
    const session = await env.MY_KV.get("session:abc", "json");

    // List keys by prefix
    const list = await env.MY_KV.list({ prefix: "session:", limit: 100 });

    // Delete
    await env.MY_KV.delete("session:abc");

    return Response.json({ session, keys: list.keys.length });
  },
};
bash
undefined

KV CLI operations

KV CLI operations

npx wrangler kv namespace create MY_KV npx wrangler kv namespace list npx wrangler kv key put --namespace-id=abc123 "config:feature-flags" '{"darkMode":true}' npx wrangler kv key get --namespace-id=abc123 "config:feature-flags" npx wrangler kv key list --namespace-id=abc123 --prefix="config:"
undefined
npx wrangler kv namespace create MY_KV npx wrangler kv namespace list npx wrangler kv key put --namespace-id=abc123 "config:feature-flags" '{"darkMode":true}' npx wrangler kv key get --namespace-id=abc123 "config:feature-flags" npx wrangler kv key list --namespace-id=abc123 --prefix="config:"
undefined

D1 Database Binding

D1数据库绑定

toml
undefined
toml
undefined

wrangler.toml

wrangler.toml

[[d1_databases]] binding = "DB" database_name = "my-app" database_id = "xxxx-yyyy-zzzz"

```typescript
// D1 SQL queries in a Worker
interface Env {
  DB: D1Database;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Parameterized query
    const { results } = await env.DB.prepare(
      "SELECT id, name, email FROM users WHERE active = ? LIMIT ?"
    )
      .bind(1, 50)
      .all();

    // Insert
    await env.DB.prepare("INSERT INTO users (name, email) VALUES (?, ?)")
      .bind("Alice", "alice@example.com")
      .run();

    // Batch multiple statements
    await env.DB.batch([
      env.DB.prepare("UPDATE users SET active = 0 WHERE last_login < ?").bind("2024-01-01"),
      env.DB.prepare("DELETE FROM sessions WHERE expires_at < ?").bind(Date.now()),
    ]);

    return Response.json(results);
  },
};
bash
undefined
[[d1_databases]] binding = "DB" database_name = "my-app" database_id = "xxxx-yyyy-zzzz"

```typescript
// D1 SQL queries in a Worker
interface Env {
  DB: D1Database;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Parameterized query
    const { results } = await env.DB.prepare(
      "SELECT id, name, email FROM users WHERE active = ? LIMIT ?"
    )
      .bind(1, 50)
      .all();

    // Insert
    await env.DB.prepare("INSERT INTO users (name, email) VALUES (?, ?)")
      .bind("Alice", "alice@example.com")
      .run();

    // Batch multiple statements
    await env.DB.batch([
      env.DB.prepare("UPDATE users SET active = 0 WHERE last_login < ?").bind("2024-01-01"),
      env.DB.prepare("DELETE FROM sessions WHERE expires_at < ?").bind(Date.now()),
    ]);

    return Response.json(results);
  },
};
bash
undefined

D1 CLI operations

D1 CLI operations

npx wrangler d1 create my-app npx wrangler d1 list npx wrangler d1 execute my-app --command="CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, active INTEGER DEFAULT 1)" npx wrangler d1 execute my-app --file=./migrations/001_init.sql npx wrangler d1 execute my-app --command="SELECT * FROM users" --json
undefined
npx wrangler d1 create my-app npx wrangler d1 list npx wrangler d1 execute my-app --command="CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT, active INTEGER DEFAULT 1)" npx wrangler d1 execute my-app --file=./migrations/001_init.sql npx wrangler d1 execute my-app --command="SELECT * FROM users" --json
undefined

Cron Triggers

定时触发器

toml
undefined
toml
undefined

wrangler.toml

wrangler.toml

[triggers] crons = [ "0 */6 * * ", # Every 6 hours "0 0 * * MON", # Every Monday at midnight "/15 * * * *", # Every 15 minutes ]

```typescript
// src/index.ts — scheduled handler
export default {
  async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
    switch (event.cron) {
      case "0 */6 * * *":
        ctx.waitUntil(cleanupExpiredSessions(env));
        break;
      case "0 0 * * MON":
        ctx.waitUntil(generateWeeklyReport(env));
        break;
    }
  },

  async fetch(request: Request, env: Env): Promise<Response> {
    return new Response("OK");
  },
};
[triggers] crons = [ "0 */6 * * ", # Every 6 hours "0 0 * * MON", # Every Monday at midnight "/15 * * * *", # Every 15 minutes ]

```typescript
// src/index.ts — scheduled handler
export default {
  async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
    switch (event.cron) {
      case "0 */6 * * *":
        ctx.waitUntil(cleanupExpiredSessions(env));
        break;
      case "0 0 * * MON":
        ctx.waitUntil(generateWeeklyReport(env));
        break;
    }
  },

  async fetch(request: Request, env: Env): Promise<Response> {
    return new Response("OK");
  },
};

Durable Objects

Durable Objects

toml
undefined
toml
undefined

wrangler.toml

wrangler.toml

[durable_objects] bindings = [ { name = "COUNTER", class_name = "Counter" } ]
[[migrations]] tag = "v1" new_classes = ["Counter"]

```typescript
// src/counter.ts — Durable Object class
export class Counter {
  state: DurableObjectState;

  constructor(state: DurableObjectState) {
    this.state = state;
  }

  async fetch(request: Request): Promise<Response> {
    let count = (await this.state.storage.get<number>("count")) || 0;
    count++;
    await this.state.storage.put("count", count);
    return Response.json({ count });
  }
}

// src/index.ts — route to Durable Object
interface Env {
  COUNTER: DurableObjectNamespace;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const id = env.COUNTER.idFromName("global-counter");
    const stub = env.COUNTER.get(id);
    return stub.fetch(request);
  },
};
[durable_objects] bindings = [ { name = "COUNTER", class_name = "Counter" } ]
[[migrations]] tag = "v1" new_classes = ["Counter"]

```typescript
// src/counter.ts — Durable Object class
export class Counter {
  state: DurableObjectState;

  constructor(state: DurableObjectState) {
    this.state = state;
  }

  async fetch(request: Request): Promise<Response> {
    let count = (await this.state.storage.get<number>("count")) || 0;
    count++;
    await this.state.storage.put("count", count);
    return Response.json({ count });
  }
}

// src/index.ts — route to Durable Object
interface Env {
  COUNTER: DurableObjectNamespace;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const id = env.COUNTER.idFromName("global-counter");
    const stub = env.COUNTER.get(id);
    return stub.fetch(request);
  },
};

Custom Routing

自定义路由

toml
undefined
toml
undefined

Route to specific zones

Route to specific zones

routes = [ { pattern = "api.example.com/v1/", zone_name = "example.com" }, { pattern = "api.example.com/v2/", zone_name = "example.com" }, ]
routes = [ { pattern = "api.example.com/v1/", zone_name = "example.com" }, { pattern = "api.example.com/v2/", zone_name = "example.com" }, ]

Or use custom domains (automatic SSL)

Or use custom domains (automatic SSL)

Dashboard: Workers > your-worker > Triggers > Custom Domains

Dashboard: Workers > your-worker > Triggers > Custom Domains

undefined
undefined

Troubleshooting

故障排查

SymptomCauseFix
Error 1101: Worker threw exception
Unhandled error in fetch handlerWrap handler in try/catch; check
wrangler tail
for stack trace
exceeded CPU time limit
Worker exceeds 10ms CPU (free) or 30s (paid)Optimize code; offload work with
ctx.waitUntil()
KV reads return stale dataKV is eventually consistent (~60s)Use
cacheTtl
option or switch to Durable Objects for strong consistency
wrangler dev
binding errors
Local bindings not configuredUse
--remote
flag or configure
preview_id
in
wrangler.toml
Secret not found in WorkerSecret set for wrong environmentVerify with
wrangler secret list --env <env>
CORS errors from browserMissing CORS headers in responseAdd
Access-Control-Allow-Origin
headers; handle OPTIONS preflight
Route not matchingPattern does not include
/*
suffix
Add
/*
to catch all paths:
api.example.com/*
症状原因解决方法
Error 1101: Worker threw exception
Fetch处理器存在未捕获的错误用try/catch包裹处理器;查看
wrangler tail
输出的堆栈跟踪
exceeded CPU time limit
Worker超出CPU时间限制(免费版10ms,付费版30s)优化代码;使用
ctx.waitUntil()
卸载后台任务
KV读取返回过期数据KV为最终一致性模型(约60s同步延迟)使用
cacheTtl
选项,或改用Durable Objects实现强一致性
wrangler dev
绑定错误
本地绑定未配置使用
--remote
参数,或在
wrangler.toml
中配置
preview_id
Worker中找不到密钥密钥配置在错误环境中使用
wrangler secret list --env <env>
验证
浏览器出现CORS错误响应缺少CORS头添加
Access-Control-Allow-Origin
头;处理OPTIONS预检请求
路由不匹配模式未包含
/*
后缀
添加
/*
以匹配所有路径:
api.example.com/*

Related Skills

相关技能

  • cloudflare-pages - Frontend deployments with Pages Functions
  • cloudflare-r2 - Object storage at the edge
  • cloudflare-zero-trust - Protect Worker endpoints with Access
  • cloudflare-pages - 使用Pages Functions部署前端
  • cloudflare-r2 - 边缘对象存储
  • cloudflare-zero-trust - 使用Access保护Worker端点