name: cloudflare-workers description: 使用 Cloudflare Workers 构建 serverless 应用程序的综合指南。当开发 Workers、配置绑定、实现运行时 API、测试 Workers、使用 Wrangler CLI、部署到生产环境或使用 JavaScript/TypeScript/Python/Rust 构建边缘函数时使用。 license: MIT version: 1.0.0
Cloudflare Workers 技能
Cloudflare Workers 是一个 serverless 执行环境,在 Cloudflare 全球 300 多个城市的边缘网络上运行 JavaScript、TypeScript、Python 和 Rust 代码。
参考
- 主要文档: https://developers.cloudflare.com/workers/
- 运行时 API: https://developers.cloudflare.com/workers/runtime-apis/
- 示例: https://developers.cloudflare.com/workers/examples/
- Wrangler CLI: https://developers.cloudflare.com/workers/wrangler/
何时使用此技能
在以下情况使用此技能:
- 创建新的 Cloudflare Workers 应用程序
- 配置 Worker 绑定(D1、KV、R2、Durable Objects 等)
- 实现 Worker 运行时 API(fetch、cache、HTMLRewriter、WebSockets)
- 使用 Wrangler 本地编写和测试 Workers
- 将 Workers 部署到生产环境
- 实现 cron 触发器和计划任务
- 构建 API 端点和中间件
- 处理 Workers 静态资源
- 为 Workers 设置 CI/CD
- 从 service workers 迁移到 ES 模块
- 调试和监控 Workers
- 优化 Worker 性能
核心概念
执行模型
V8 隔离: Workers 在轻量级 V8 隔离中运行(非容器):
- 毫秒级冷启动(比容器更快)
- 零基础设施管理
- 自动全球扩展
- 按请求付费定价
请求生命周期:
- 请求到达最近的 Cloudflare 数据中心
- Worker 在 V8 隔离中执行
- 响应返回给客户端
- 隔离可能被后续请求重用
关键特性:
- 最大 CPU 时间:50ms(免费版),30 秒(付费版)
- 最大内存:128MB
- 在边缘执行(最靠近用户)
- 请求之间无状态(使用 Durable Objects 处理状态)
Worker 格式
ES 模块(推荐):
// 现代语法,使用 export default
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
return new Response('Hello World!');
}
};
Service Worker(旧版):
// 旧格式
addEventListener('fetch', (event) => {
event.respondWith(new Response('Hello World!'));
});
处理器类型
Workers 支持多种事件类型:
Fetch 处理器(HTTP 请求):
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
return new Response('Hello');
}
};
Scheduled 处理器(Cron 任务):
export default {
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
// 按计划运行
await fetch('https://api.example.com/cleanup');
}
};
Queue 处理器(消息处理):
export default {
async queue(batch: MessageBatch, env: Env, ctx: ExecutionContext): Promise<void> {
for (const message of batch.messages) {
await processMessage(message.body);
}
}
};
Email 处理器(邮件路由):
export default {
async email(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): Promise<void> {
await message.forward('destination@example.com');
}
};
Tail 处理器(日志聚合):
export default {
async tail(events: TraceItem[], env: Env, ctx: ExecutionContext): Promise<void> {
// 处理来自其他 Workers 的日志
}
};
Wrangler CLI
安装与设置
# 全局安装
npm install -g wrangler
# 或使用 npx
npx wrangler <command>
# 登录到 Cloudflare
wrangler login
# 检查版本
wrangler --version
项目管理
# 创建新 Worker
wrangler init my-worker
# 选项:TypeScript、Git、部署
# 使用模板创建
wrangler init my-worker --template <template-url>
# 开发服务器
wrangler dev # 本地模式
wrangler dev --remote # 远程模式(实际边缘)
wrangler dev --port 8080 # 自定义端口
# 部署
wrangler deploy # 生产环境
wrangler deploy --dry-run # 预览更改
wrangler deploy --env staging # 特定环境
# 日志
wrangler tail # 实时日志
wrangler tail --format pretty # 格式化输出
wrangler tail --status error # 按状态过滤
# 版本与回滚
wrangler deployments list
wrangler rollback [version-id]
wrangler versions list
配置(wrangler.toml)
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
compatibility_flags = ["nodejs_compat"]
# 路由
routes = [
{ pattern = "example.com/*", zone_name = "example.com" }
]
# 或使用自定义域名
# [[routes]]
# pattern = "api.example.com/*"
# custom_domain = true
# 环境变量
[vars]
ENVIRONMENT = "production"
API_VERSION = "v1"
# Cron 触发器
[triggers]
crons = ["0 0 * * *"] # 每天午夜
# 构建配置
[build]
command = "npm run build"
watch_dirs = ["src"]
# 环境
[env.staging]
name = "my-worker-staging"
routes = [
{ pattern = "staging.example.com/*", zone_name = "example.com" }
]
[env.staging.vars]
ENVIRONMENT = "staging"
密码管理
# 添加密码
wrangler secret put API_KEY
# 提示时输入值
# 列出密码
wrangler secret list
# 删除密码
wrangler secret delete API_KEY
# 批量上传
echo "VALUE" | wrangler secret put API_KEY
运行时 API
Fetch API
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
// 解析 URL
const url = new URL(request.url);
// 请求属性
const method = request.method;
const headers = request.headers;
const body = await request.text();
// 子请求
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' })
});
const data = await response.json();
// 响应
return new Response(JSON.stringify(data), {
status: 200,
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, max-age=3600'
}
});
}
};
Headers API
// 读取头
const userAgent = request.headers.get('User-Agent');
const allHeaders = Object.fromEntries(request.headers);
// 设置头
const headers = new Headers();
headers.set('Content-Type', 'application/json');
headers.append('X-Custom-Header', 'value');
// Cloudflare 特定头
const country = request.cf?.country;
const colo = request.cf?.colo;
const clientIP = request.headers.get('CF-Connecting-IP');
// 响应带头
return new Response(body, { headers });
Cache API
export default {
async fetch(request: Request): Promise<Response> {
const cache = caches.default;
// 检查缓存
let response = await cache.match(request);
if (!response) {
// 缓存未命中 - 从源获取
response = await fetch(request);
// 克隆并缓存响应
const cacheResponse = response.clone();
ctx.waitUntil(cache.put(request, cacheResponse));
}
return response;
}
};
使用自定义键缓存:
const cacheKey = new Request(url.toString(), request);
const response = await cache.match(cacheKey);
if (!response) {
response = await fetch(request);
ctx.waitUntil(cache.put(cacheKey, response.clone()));
}
使用 TTL 缓存:
const response = await fetch('https://api.example.com/data', {
cf: {
cacheTtl: 3600,
cacheEverything: true,
cacheKey: 'custom-key'
}
});
HTMLRewriter
export default {
async fetch(request: Request): Promise<Response> {
const response = await fetch(request);
return new HTMLRewriter()
.on('title', {
element(element) {
element.setInnerContent('New Title');
}
})
.on('a[href]', {
element(element) {
const href = element.getAttribute('href');
element.setAttribute('href', href.replace('http://', 'https://'));
}
})
.on('script', {
element(element) {
element.remove();
}
})
.transform(response);
}
};
文本操作:
new HTMLRewriter()
.on('p', {
text(text) {
if (text.text.includes('replace-me')) {
text.replace('new-text');
}
}
})
.transform(response);
WebSockets
export default {
async fetch(request: Request): Promise<Response> {
const upgradeHeader = request.headers.get('Upgrade');
if (upgradeHeader !== 'websocket') {
return new Response('Expected WebSocket', { status: 426 });
}
const pair = new WebSocketPair();
const [client, server] = Object.values(pair);
// 接受 WebSocket 连接
server.accept();
// 处理消息
server.addEventListener('message', (event) => {
server.send(`Echo: ${event.data}`);
});
server.addEventListener('close', () => {
console.log('WebSocket closed');
});
return new Response(null, {
status: 101,
webSocket: client
});
}
};
Streams API
// 可读流
const { readable, writable } = new TransformStream();
const writer = writable.getWriter();
writer.write(new TextEncoder().encode('chunk 1'));
writer.write(new TextEncoder().encode('chunk 2'));
writer.close();
return new Response(readable, {
headers: { 'Content-Type': 'text/plain' }
});
流转换:
const response = await fetch('https://example.com/large-file');
const { readable, writable } = new TransformStream({
transform(chunk, controller) {
// 处理块
controller.enqueue(chunk);
}
});
response.body.pipeTo(writable);
return new Response(readable);
Context API
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
// waitUntil: 响应发送后运行任务
ctx.waitUntil(
fetch('https://analytics.example.com/log', {
method: 'POST',
body: JSON.stringify({ url: request.url })
})
);
// passThroughOnException: 错误时继续到源
ctx.passThroughOnException();
return new Response('OK');
}
};
Web Crypto API
// 生成哈希
const data = new TextEncoder().encode('message');
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
// HMAC 签名
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign', 'verify']
);
const signature = await crypto.subtle.sign('HMAC', key, data);
// 验证
const valid = await crypto.subtle.verify('HMAC', key, signature, data);
// 随机值
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
const uuid = crypto.randomUUID();
// 时序安全比较
const equal = crypto.timingSafeEqual(buffer1, buffer2);
绑定
环境变量
// wrangler.toml
[vars]
API_URL = "https://api.example.com"
// 使用
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const apiUrl = env.API_URL;
return new Response(apiUrl);
}
};
KV 命名空间
# wrangler.toml
[[kv_namespaces]]
binding = "MY_KV"
id = "your-namespace-id"
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 放置
await env.MY_KV.put('key', 'value', {
expirationTtl: 3600,
metadata: { userId: '123' }
});
// 获取
const value = await env.MY_KV.get('key');
const json = await env.MY_KV.get('key', 'json');
const buffer = await env.MY_KV.get('key', 'arrayBuffer');
const stream = await env.MY_KV.get('key', 'stream');
// 获取带元数据
const { value, metadata } = await env.MY_KV.getWithMetadata('key');
// 删除
await env.MY_KV.delete('key');
// 列出
const list = await env.MY_KV.list({ prefix: 'user:' });
return new Response(value);
}
};
R2 存储桶
# wrangler.toml
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 放置对象
await env.MY_BUCKET.put('file.txt', 'content', {
httpMetadata: {
contentType: 'text/plain',
contentLanguage: 'en-US',
cacheControl: 'public, max-age=3600'
},
customMetadata: {
uploadedBy: 'user123'
}
});
// 获取对象
const object = await env.MY_BUCKET.get('file.txt');
if (!object) {
return new Response('Not Found', { status: 404 });
}
// 返回对象
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',
'ETag': object.etag
}
});
// 删除对象
await env.MY_BUCKET.delete('file.txt');
// 列出对象
const listed = await env.MY_BUCKET.list({ prefix: 'uploads/' });
// 多部分上传
const multipart = await env.MY_BUCKET.createMultipartUpload('large-file.bin');
const part1 = await multipart.uploadPart(1, chunk1);
const part2 = await multipart.uploadPart(2, chunk2);
await multipart.complete([part1, part2]);
}
};
D1 数据库
# wrangler.toml
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-database-id"
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 查询
const result = await env.DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(userId).first();
// 插入
const info = await env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind('Alice', 'alice@example.com').run();
// 批处理(原子性)
const results = await env.DB.batch([
env.DB.prepare('UPDATE accounts SET balance = balance - 100 WHERE id = ?').bind(1),
env.DB.prepare('UPDATE accounts SET balance = balance + 100 WHERE id = ?').bind(2)
]);
// 所有结果
const { results: rows } = await env.DB.prepare(
'SELECT * FROM users'
).all();
return new Response(JSON.stringify(result));
}
};
Durable Objects
# wrangler.toml
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
script_name = "my-worker"
// 定义 Durable Object
export class Counter {
state: DurableObjectState;
constructor(state: DurableObjectState, env: Env) {
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 new Response(JSON.stringify({ count }));
}
// 警报处理器
async alarm(): Promise<void> {
// 在计划时间运行
await this.state.storage.deleteAll();
}
}
// 在 Worker 中使用
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const id = env.COUNTER.idFromName('global');
const counter = env.COUNTER.get(id);
return counter.fetch(request);
}
};
队列
# wrangler.toml
[[queues.producers]]
binding = "MY_QUEUE"
queue = "my-queue"
[[queues.consumers]]
queue = "my-queue"
max_batch_size = 10
max_batch_timeout = 30
// 生产者
export default {
async fetch(request: Request, env: Env): Promise<Response> {
await env.MY_QUEUE.send({
type: 'email',
to: 'user@example.com'
});
// 批量发送
await env.MY_QUEUE.sendBatch([
{ body: { message: 1 } },
{ body: { message: 2 } }
]);
return new Response('Queued');
}
};
// 消费者
export default {
async queue(batch: MessageBatch, env: Env, ctx: ExecutionContext): Promise<void> {
for (const message of batch.messages) {
try {
await processMessage(message.body);
message.ack();
} catch (error) {
message.retry();
}
}
}
};
Workers AI
# wrangler.toml
[ai]
binding = "AI"
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 文本生成
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
messages: [
{ role: 'user', content: 'What is edge computing?' }
]
});
// 图像生成
const imageResponse = await env.AI.run('@cf/stabilityai/stable-diffusion-xl-base-1.0', {
prompt: 'A sunset over mountains'
});
// 嵌入
const embeddings = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: ['Hello world', 'Cloudflare Workers']
});
// 语音识别
const audio = await request.arrayBuffer();
const transcription = await env.AI.run('@cf/openai/whisper', {
audio: [...new Uint8Array(audio)]
});
return new Response(JSON.stringify(response));
}
};
Vectorize(向量数据库)
# wrangler.toml
[[vectorize]]
binding = "VECTORIZE_INDEX"
index_name = "my-index"
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 插入向量
await env.VECTORIZE_INDEX.insert([
{
id: '1',
values: [0.1, 0.2, 0.3],
metadata: { text: 'Hello world' }
}
]);
// 查询
const results = await env.VECTORIZE_INDEX.query(
[0.1, 0.2, 0.3],
{ topK: 5 }
);
return new Response(JSON.stringify(results));
}
};
开发模式
路由
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
// 按路径路由
switch (url.pathname) {
case '/':
return new Response('Home');
case '/about':
return new Response('About');
default:
return new Response('Not Found', { status: 404 });
}
}
};
使用 Hono 框架:
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Home'));
app.get('/api/users/:id', async (c) => {
const id = c.req.param('id');
const user = await getUser(id);
return c.json(user);
});
export default app;
中间件模式
async function auth(request: Request, env: Env): Promise<Response | null> {
const token = request.headers.get('Authorization');
if (!token) {
return new Response('Unauthorized', { status: 401 });
}
return null; // 继续
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const authResponse = await auth(request, env);
if (authResponse) return authResponse;
// 继续处理请求
return new Response('Protected content');
}
};
错误处理
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
try {
const response = await processRequest(request, env);
return response;
} catch (error) {
console.error('Error:', error);
// 记录到外部服务
ctx.waitUntil(
fetch('https://logging.example.com/error', {
method: 'POST',
body: JSON.stringify({
error: error.message,
stack: error.stack,
url: request.url
})
})
);
return new Response('Internal Server Error', { status: 500 });
}
}
};
CORS
function corsHeaders(origin: string) {
return {
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400'
};
}
export default {
async fetch(request: Request): Promise<Response> {
const origin = request.headers.get('Origin') || '*';
// 处理预检请求
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: corsHeaders(origin)
});
}
// 处理请求
const response = await handleRequest(request);
// 添加 CORS 头
const headers = new Headers(response.headers);
Object.entries(corsHeaders(origin)).forEach(([key, value]) => {
headers.set(key, value);
});
return new Response(response.body, {
status: response.status,
headers
});
}
};
速率限制
async function rateLimit(ip: string, env: Env): Promise<boolean> {
const key = `ratelimit:${ip}`;
const limit = 100;
const window = 60;
const current = await env.MY_KV.get(key);
const count = current ? parseInt(current) : 0;
if (count >= limit) {
return false;
}
await env.MY_KV.put(key, (count + 1).toString(), {
expirationTtl: window
});
return true;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
if (!await rateLimit(ip, env)) {
return new Response('Rate limit exceeded', { status: 429 });
}
return new Response('OK');
}
};
测试
使用 Wrangler 本地测试
# 启动开发服务器
wrangler dev
# 使用 curl 测试
curl http://localhost:8787
# 远程开发(使用实际边缘)
wrangler dev --remote
使用 Vitest 单元测试
npm install -D vitest @cloudflare/vitest-pool-workers
vitest.config.ts:
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';
export default defineWorkersConfig({
test: {
poolOptions: {
workers: {
wrangler: { configPath: './wrangler.toml' },
},
},
},
});
测试文件:
import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test';
import { describe, it, expect } from 'vitest';
import worker from '../src/index';
describe('Worker', () => {
it('responds with Hello World', async () => {
const request = new Request('http://example.com');
const ctx = createExecutionContext();
const response = await worker.fetch(request, env, ctx);
await waitOnExecutionContext(ctx);
expect(await response.text()).toBe('Hello World!');
});
});
集成测试
import { unstable_dev } from 'wrangler';
describe('Worker integration tests', () => {
let worker;
beforeAll(async () => {
worker = await unstable_dev('src/index.ts', {
experimental: { disableExperimentalWarning: true }
});
});
afterAll(async () => {
await worker.stop();
});
it('should return 200', async () => {
const resp = await worker.fetch();
expect(resp.status).toBe(200);
});
});
部署
基本部署
# 部署到生产环境
wrangler deploy
# 部署到特定环境
wrangler deploy --env staging
# 预览部署
wrangler deploy --dry-run
环境
# wrangler.toml
name = "my-worker"
[env.staging]
name = "my-worker-staging"
routes = [
{ pattern = "staging.example.com/*", zone_name = "example.com" }
]
[env.production]
name = "my-worker-production"
routes = [
{ pattern = "api.example.com/*", zone_name = "example.com" }
]
wrangler deploy --env staging
wrangler deploy --env production
使用 GitHub Actions CI/CD
# .github/workflows/deploy.yml
name: Deploy Worker
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm install
- run: npm test
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
渐进式部署
# 部署到 10% 的流量
wrangler versions deploy --percentage 10
# 提升到 100%
wrangler versions deploy --percentage 100
# 回滚
wrangler rollback
静态资源
配置
# wrangler.toml
name = "my-worker"
main = "src/index.ts"
[assets]
directory = "./public"
binding = "ASSETS"
服务静态资源
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// 服务静态资源
const asset = await env.ASSETS.fetch(request);
if (asset.status === 200) {
return asset;
}
// 回退到动态响应
return new Response('Not Found', { status: 404 });
}
};
单页应用(SPA)
[assets]
directory = "./dist"
binding = "ASSETS"
html_handling = "force-https"
not_found_handling = "single-page-application"
可观测性
日志
export default {
async fetch(request: Request): Promise<Response> {
console.log('Request URL:', request.url);
console.error('Error occurred');
console.warn('Warning message');
// 结构化日志
console.log(JSON.stringify({
level: 'info',
message: 'Request processed',
url: request.url,
timestamp: new Date().toISOString()
}));
return new Response('OK');
}
};
实时日志
# 尾随日志
wrangler tail
# 按状态过滤
wrangler tail --status error
# 按方法过滤
wrangler tail --method POST
# 按采样过滤
wrangler tail --sampling-rate 0.5
分析
// 使用 Analytics Engine 绑定
export default {
async fetch(request: Request, env: Env): Promise<Response> {
env.ANALYTICS.writeDataPoint({
blobs: ['example'],
doubles: [123.45],
indexes: ['index_value']
});
return new Response('Logged');
}
};
错误追踪(Sentry)
import * as Sentry from '@sentry/cloudflare';
export default {
async fetch(request: Request, env: Env): Promise<Response> {
Sentry.init({
dsn: env.SENTRY_DSN,
environment: env.ENVIRONMENT
});
try {
return await handleRequest(request);
} catch (error) {
Sentry.captureException(error);
throw error;
}
}
};
性能优化
最佳实践
- 最小化包大小: 保持 Workers 在 1MB 以下
- 使用绑定: 直接绑定比 fetch 更快
- 积极缓存: 使用 Cache API 和 KV
- 流式传输大响应: 使用流而不是缓冲
- 批处理操作: 使用 batch() 合并 D1 查询
- 使用 waitUntil 处理后台任务: 不要阻塞响应
- 避免同步 I/O: 所有操作应为异步
代码分割
// 懒加载大型依赖
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === '/heavy') {
const { processHeavy } = await import('./heavy');
return processHeavy(request);
}
return new Response('OK');
}
};
缓存策略
const CACHE_TTL = 3600;
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const cache = caches.default;
const cacheKey = new Request(request.url);
// 1. 检查边缘缓存
let response = await cache.match(cacheKey);
if (response) return response;
// 2. 检查 KV 缓存
const kvCached = await env.MY_KV.get(request.url);
if (kvCached) {
response = new Response(kvCached);
ctx.waitUntil(cache.put(cacheKey, response.clone()));
return response;
}
// 3. 从源获取
response = await fetch(request);
// 4. 存储到两个缓存
ctx.waitUntil(Promise.all([
cache.put(cacheKey, response.clone()),
env.MY_KV.put(request.url, await response.clone().text(), {
expirationTtl: CACHE_TTL
})
]));
return response;
}
};
常见模式
API 网关
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
const app = new Hono();
app.use('*', cors());
app.use('*', logger());
// 路由
app.get('/api/users', async (c) => {
const users = await c.env.DB.prepare('SELECT * FROM users').all();
return c.json(users.results);
});
app.get('/api/users/:id', async (c) => {
const id = c.req.param('id');
const user = await c.env.DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(id).first();
if (!user) {
return c.json({ error: 'Not found' }, 404);
}
return c.json(user);
});
app.post('/api/users', async (c) => {
const body = await c.req.json();
const result = await c.env.DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(body.name, body.email).run();
return c.json({ id: result.meta.last_row_id }, 201);
});
export default app;
认证
import { sign, verify } from 'hono/jwt';
async function authenticate(request: Request, env: Env): Promise<any> {
const authHeader = request.headers.get('Authorization');
if (!authHeader?.startsWith('Bearer ')) {
throw new Error('Missing token');
}
const token = authHeader.substring(7);
const payload = await verify(token, env.JWT_SECRET);
return payload;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
try {
const user = await authenticate(request, env);
return new Response(`Hello ${user.name}`);
} catch (error) {
return new Response('Unauthorized', { status: 401 });
}
}
};
图像代理
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
const imageUrl = url.searchParams.get('url');
if (!imageUrl) {
return new Response('Missing url parameter', { status: 400 });
}
const response = await fetch(imageUrl);
return new Response(response.body, {
headers: {
'Content-Type': response.headers.get('Content-Type') || 'image/jpeg',
'Cache-Control': 'public, max-age=86400',
'CDN-Cache-Control': 'public, max-age=31536000'
}
});
}
};
Webhook 处理器
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
// 验证签名
const signature = request.headers.get('X-Hub-Signature-256');
const body = await request.text();
const valid = await verifySignature(body, signature, env.WEBHOOK_SECRET);
if (!valid) {
return new Response('Invalid signature', { status: 401 });
}
// 排队处理
ctx.waitUntil(
env.WEBHOOK_QUEUE.send(JSON.parse(body))
);
return new Response('OK');
}
};
故障排除
常见问题
CPU 时间超出:
- 优化昂贵操作
- 对大数据使用流
- 将处理移动到 Durable Objects
- 考虑跨多个请求拆分工作
内存超出:
- 流式传输大响应而不是缓冲
- 清除未使用的变量
- 使用分块处理
脚本大小过大:
- 移除未使用的依赖
- 使用代码分割
- 最小化生产构建
- 检查
wrangler deploy --dry-run --outdir=dist输出
绑定未找到:
- 检查 wrangler.toml 配置
- 确保绑定名称匹配 env 属性
- 配置更改后重新部署
CORS 错误:
- 添加正确的 CORS 头
- 处理 OPTIONS 请求
- 检查允许的源
调试
# 本地调试
wrangler dev --local
# 远程调试(真实边缘环境)
wrangler dev --remote
# 检查包
wrangler deploy --dry-run --outdir=dist
# 检查日志
wrangler tail --format pretty
资源
- 主要文档: https://developers.cloudflare.com/workers/
- 示例: https://developers.cloudflare.com/workers/examples/
- Discord: https://discord.cloudflare.com
- GitHub: https://github.com/cloudflare/workers-sdk
- 状态: https://www.cloudflarestatus.com
- 定价: https://developers.cloudflare.com/workers/platform/pricing/
实施清单
初始设置
- [ ] 安装 Wrangler CLI
- [ ] 登录 Cloudflare 账户
- [ ] 创建新 Worker 项目
- [ ] 配置 wrangler.toml
- [ ] 使用
wrangler dev本地测试
开发
- [ ] 实现 fetch 处理器
- [ ] 添加错误处理
- [ ] 设置 TypeScript 类型
- [ ] 配置绑定(KV、D1、R2 等)
- [ ] 添加环境变量
- [ ] 实施缓存策略
测试
- [ ] 使用 Vitest 编写单元测试
- [ ] 使用 wrangler dev 本地测试
- [ ] 在远程边缘测试
- [ ] 验证绑定工作
部署
- [ ] 设置环境(staging、production)
- [ ] 配置路由或自定义域名
- [ ] 添加密码
- [ ] 设置 CI/CD 流水线
- [ ] 部署到生产环境
- [ ] 监控日志和分析
生产
- [ ] 设置错误追踪
- [ ] 配置分析
- [ ] 实施速率限制
- [ ] 添加监控警报
- [ ] 文档化 API 端点
- [ ] 设置回滚程序