cloudflare-workers
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare 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: or set
wrangler login.CLOUDFLARE_API_TOKEN
- 本地安装Node.js 18+版本。
- Wrangler CLI: .
npm install -g wrangler - Cloudflare账户(免费计划支持每日10万次请求)。
- 完成认证:或设置
wrangler login。CLOUDFLARE_API_TOKEN
Quick Start
快速开始
bash
undefinedbash
undefinedScaffold 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
undefinednpx wrangler deploy
undefinedEssential Wrangler Commands
Wrangler核心命令
bash
undefinedbash
undefinedLocal 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
undefinednpx wrangler rollback
undefinedWrangler Configuration
Wrangler配置
toml
undefinedtoml
undefinedwrangler.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"
undefinedWorker 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
undefinedtoml
undefinedwrangler.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
undefinedKV 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:"
undefinednpx 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:"
undefinedD1 Database Binding
D1数据库绑定
toml
undefinedtoml
undefinedwrangler.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
undefinedD1 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
undefinednpx 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
undefinedCron Triggers
定时触发器
toml
undefinedtoml
undefinedwrangler.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
undefinedtoml
undefinedwrangler.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
undefinedtoml
undefinedRoute 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
undefinedundefinedTroubleshooting
故障排查
| Symptom | Cause | Fix |
|---|---|---|
| Unhandled error in fetch handler | Wrap handler in try/catch; check |
| Worker exceeds 10ms CPU (free) or 30s (paid) | Optimize code; offload work with |
| KV reads return stale data | KV is eventually consistent (~60s) | Use |
| Local bindings not configured | Use |
| Secret not found in Worker | Secret set for wrong environment | Verify with |
| CORS errors from browser | Missing CORS headers in response | Add |
| Route not matching | Pattern does not include | Add |
| 症状 | 原因 | 解决方法 |
|---|---|---|
| Fetch处理器存在未捕获的错误 | 用try/catch包裹处理器;查看 |
| Worker超出CPU时间限制(免费版10ms,付费版30s) | 优化代码;使用 |
| KV读取返回过期数据 | KV为最终一致性模型(约60s同步延迟) | 使用 |
| 本地绑定未配置 | 使用 |
| Worker中找不到密钥 | 密钥配置在错误环境中 | 使用 |
| 浏览器出现CORS错误 | 响应缺少CORS头 | 添加 |
| 路由不匹配 | 模式未包含 | 添加 |
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端点