CloudflareWorkers开发技能Skill cloudflare-workers

Cloudflare Workers 是一种 serverless 执行环境,允许开发者在 Cloudflare 的全球边缘网络上运行 JavaScript、TypeScript、Python 和 Rust 代码。它用于构建高性能的 web 应用、API 网关、图像处理、实时通信等场景,支持多种绑定如 KV、D1、R2、Durable Objects。关键词包括 serverless、边缘计算、JavaScript、TypeScript、Python、Rust、Cloudflare、Wrangler、KV、D1、R2、Durable Objects、API 开发、WebSockets。

Serverless 0 次安装 0 次浏览 更新于 3/18/2026

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 代码。

参考

何时使用此技能

在以下情况使用此技能:

  • 创建新的 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 隔离中运行(非容器):

  • 毫秒级冷启动(比容器更快)
  • 零基础设施管理
  • 自动全球扩展
  • 按请求付费定价

请求生命周期:

  1. 请求到达最近的 Cloudflare 数据中心
  2. Worker 在 V8 隔离中执行
  3. 响应返回给客户端
  4. 隔离可能被后续请求重用

关键特性:

  • 最大 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;
    }
  }
};

性能优化

最佳实践

  1. 最小化包大小: 保持 Workers 在 1MB 以下
  2. 使用绑定: 直接绑定比 fetch 更快
  3. 积极缓存: 使用 Cache API 和 KV
  4. 流式传输大响应: 使用流而不是缓冲
  5. 批处理操作: 使用 batch() 合并 D1 查询
  6. 使用 waitUntil 处理后台任务: 不要阻塞响应
  7. 避免同步 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

资源

实施清单

初始设置

  • [ ] 安装 Wrangler CLI
  • [ ] 登录 Cloudflare 账户
  • [ ] 创建新 Worker 项目
  • [ ] 配置 wrangler.toml
  • [ ] 使用 wrangler dev 本地测试

开发

  • [ ] 实现 fetch 处理器
  • [ ] 添加错误处理
  • [ ] 设置 TypeScript 类型
  • [ ] 配置绑定(KV、D1、R2 等)
  • [ ] 添加环境变量
  • [ ] 实施缓存策略

测试

  • [ ] 使用 Vitest 编写单元测试
  • [ ] 使用 wrangler dev 本地测试
  • [ ] 在远程边缘测试
  • [ ] 验证绑定工作

部署

  • [ ] 设置环境(staging、production)
  • [ ] 配置路由或自定义域名
  • [ ] 添加密码
  • [ ] 设置 CI/CD 流水线
  • [ ] 部署到生产环境
  • [ ] 监控日志和分析

生产

  • [ ] 设置错误追踪
  • [ ] 配置分析
  • [ ] 实施速率限制
  • [ ] 添加监控警报
  • [ ] 文档化 API 端点
  • [ ] 设置回滚程序