mcpField
C
cloudflare-development

cloudflare-development

github.com/mindrally云与 DevOps287695 次安装3 周前更新
代码仓库

关于 cloudflare-development

面向使用 Cloudflare 边缘平台开发应用的技能,适用于使用 Workers、Pages 及相关存储的开发者,涵盖实现、安全、性能、测试和部署实践。

主要功能

  1. 01Workers 与 Pages 开发
  2. 02KV、D1 和 R2 使用指引
  3. 03Durable Objects 模式
  4. 04边缘安全实践
  5. 05测试与部署指引

适用场景

  1. 01实现 Cloudflare Worker API
  2. 02为边缘应用选择存储方案
  3. 03测试并部署 Cloudflare 应用

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mindrally/skills --skill cloudflare-development

安装后在 Claude Code 中输入/cloudflare-development确认已加载。

详细介绍

Cloudflare 开发最佳实践

概述

本技能提供了在 Cloudflare 边缘平台上开发应用的全面指南,涵盖 Workers、Pages、KV 存储、D1 数据库、R2 对象存储和 Durable Objects。

核心原则

  • 编写轻量、快速的代码,针对边缘执行进行优化
  • 尽量缩短冷启动时间和执行时长
  • 针对不同用例选择合适的存储解决方案
  • 遵循边缘计算安全最佳实践
  • 利用 Cloudflare 的全球网络提升性能

Cloudflare Workers 指南

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

      // Route handling
      if (url.pathname === '/api/data') {
        return handleApiRequest(request, env);
      }

      return new Response('Not Found', { status: 404 });
    } catch (error) {
      console.error('Worker error:', error);
      return new Response('Internal Server Error', { status: 500 });
    }
  },
} satisfies ExportedHandler<Env>;
环境类型
interface Env {
  // KV Namespaces
  MY_KV: KVNamespace;

  // D1 Databases
  MY_DB: D1Database;

  // R2 Buckets
  MY_BUCKET: R2Bucket;

  // Durable Objects
  MY_DURABLE_OBJECT: DurableObjectNamespace;

  // Environment Variables
  API_KEY: string;
}
最佳实践
  • 使用 TypeScript 确保类型安全
  • 在边缘环境中妥善处理错误
  • 实施恰当的请求验证
  • 使用 ctx.waitUntil() 处理后台任务
  • 尽可能减少外部 API 调用

Wrangler 配置

wrangler.toml 结构
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[vars]
ENVIRONMENT = "production"

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

[[d1_databases]]
binding = "MY_DB"
database_name = "my-database"
database_id = "def456"

[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"

[durable_objects]
bindings = [
  { name = "MY_DURABLE_OBJECT", class_name = "MyDurableObject" }
]

[[migrations]]
tag = "v1"
new_classes = ["MyDurableObject"]

KV 存储指南

使用模式
// Writing to KV
await env.MY_KV.put('key', JSON.stringify(data), {
  expirationTtl: 3600, // 1 hour
  metadata: { version: '1.0' },
});

// Reading from KV
const value = await env.MY_KV.get('key', { type: 'json' });

// Listing keys
const list = await env.MY_KV.list({ prefix: 'user:' });
最佳实践
  • 使用 KV 处理读密集型负载,并接受最终一致性
  • 为缓存数据设置恰当的 TTL
  • 使用元数据补充键的信息
  • 实施缓存失效策略
  • 注意 KV 的最终一致性模型

D1 数据库指南

查询模式
// Parameterized queries (prevent SQL injection)
const results = await env.MY_DB
  .prepare('SELECT * FROM users WHERE id = ?')
  .bind(userId)
  .all();

// Batch operations
const batch = await env.MY_DB.batch([
  env.MY_DB.prepare('INSERT INTO logs (message) VALUES (?)').bind('log1'),
  env.MY_DB.prepare('INSERT INTO logs (message) VALUES (?)').bind('log2'),
]);

// First result only
const user = await env.MY_DB
  .prepare('SELECT * FROM users WHERE email = ?')
  .bind(email)
  .first();
架构管理
-- migrations/0001_initial.sql
CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  email TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);
最佳实践
  • 始终使用参数化查询
  • 创建适当的索引
  • 多次写入时使用批处理操作
  • 保持查询简单高效
  • 使用迁移管理架构变更

R2 对象存储指南

使用模式
// Upload object
await env.MY_BUCKET.put('uploads/file.pdf', fileData, {
  httpMetadata: {
    contentType: 'application/pdf',
  },
  customMetadata: {
    uploadedBy: userId,
  },
});

// Download object
const object = await env.MY_BUCKET.get('uploads/file.pdf');
if (object) {
  return new Response(object.body, {
    headers: {
      'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',
    },
  });
}

// List objects
const list = await env.MY_BUCKET.list({ prefix: 'uploads/' });

// Delete object
await env.MY_BUCKET.delete('uploads/file.pdf');
最佳实践
  • 设置恰当的内容类型
  • 大文件使用分段上传
  • 实施恰当的访问控制
  • 使用预签名 URL 直接从客户端上传
  • 使用有意义的前缀组织对象

Durable Objects 指南

实现
export class ChatRoom implements DurableObject {
  private state: DurableObjectState;
  private sessions: Map<WebSocket, { id: string }>;

  constructor(state: DurableObjectState, env: Env) {
    this.state = state;
    this.sessions = new Map();
  }

  async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname === '/websocket') {
      const pair = new WebSocketPair();
      await this.handleSession(pair[1]);
      return new Response(null, { status: 101, webSocket: pair[0] });
    }

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

  async handleSession(webSocket: WebSocket) {
    webSocket.accept();

    webSocket.addEventListener('message', async (event) => {
      // Handle messages
    });

    webSocket.addEventListener('close', () => {
      this.sessions.delete(webSocket);
    });
  }
}
最佳实践
  • 用于协调和有状态逻辑
  • 妥善处理 WebSocket
  • 使用存储 API 实现持久化
  • 通过处理休眠状态来优化成本
  • 针对单点协调模式进行设计

Cloudflare Pages 指南

项目结构
my-pages-project/
├── public/           # Static assets
├── functions/        # Pages Functions
│   ├── api/
│   │   └── [endpoint].ts
│   └── _middleware.ts
├── src/              # Application source
└── wrangler.toml     # Configuration
Pages Functions
// functions/api/users.ts
export const onRequestGet: PagesFunction<Env> = async (context) => {
  const users = await context.env.MY_DB
    .prepare('SELECT * FROM users')
    .all();

  return Response.json(users.results);
};

export const onRequestPost: PagesFunction<Env> = async (context) => {
  const body = await context.request.json();
  // Handle POST
  return Response.json({ success: true });
};

边缘安全最佳实践

请求验证
function validateRequest(request: Request): boolean {
  // Check content type
  const contentType = request.headers.get('Content-Type');
  if (request.method === 'POST' && !contentType?.includes('application/json')) {
    return false;
  }

  // Check origin (CORS)
  const origin = request.headers.get('Origin');
  if (origin && !ALLOWED_ORIGINS.includes(origin)) {
    return false;
  }

  return true;
}
身份验证
async function verifyAuth(request: Request, env: Env): Promise<boolean> {
  const authHeader = request.headers.get('Authorization');
  if (!authHeader?.startsWith('Bearer ')) {
    return false;
  }

  const token = authHeader.slice(7);
  // Verify JWT or API key
  return await verifyToken(token, env);
}
速率限制
async function checkRateLimit(ip: string, env: Env): Promise<boolean> {
  const key = `ratelimit:${ip}`;
  const current = await env.MY_KV.get(key, { type: 'json' }) as number || 0;

  if (current >= 100) { // 100 requests per window
    return false;
  }

  await env.MY_KV.put(key, JSON.stringify(current + 1), {
    expirationTtl: 60, // 1 minute window
  });

  return true;
}

性能优化

缓存策略
// Cache API usage
const cache = caches.default;

async function handleRequest(request: Request): Promise<Response> {
  // Check cache
  const cached = await cache.match(request);
  if (cached) {
    return cached;
  }

  // Generate response
  const response = await generateResponse(request);

  // Cache response
  const cacheResponse = new Response(response.body, response);
  cacheResponse.headers.set('Cache-Control', 'public, max-age=3600');
  ctx.waitUntil(cache.put(request, cacheResponse.clone()));

  return cacheResponse;
}
后台处理
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    // Respond immediately
    const response = Response.json({ status: 'accepted' });

    // Process in background
    ctx.waitUntil(processInBackground(request, env));

    return response;
  },
};

测试

本地开发
# Start local development server
wrangler dev

# Run with local persistence
wrangler dev --persist

# Test with specific environment
wrangler dev --env staging
单元测试
import { unstable_dev } from 'wrangler';

describe('Worker', () => {
  let worker: UnstableDevWorker;

  beforeAll(async () => {
    worker = await unstable_dev('src/index.ts', {
      experimental: { disableExperimentalWarning: true },
    });
  });

  afterAll(async () => {
    await worker.stop();
  });

  test('returns 200 for valid request', async () => {
    const response = await worker.fetch('/api/health');
    expect(response.status).toBe(200);
  });
});

部署

生产环境部署
# Deploy to production
wrangler deploy

# Deploy to specific environment
wrangler deploy --env production

# Deploy with secrets
wrangler secret put API_KEY
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: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}

应避免的常见问题

  1. 未能在边缘环境中妥善处理错误
  2. 进行过多外部 API 调用
  3. 忽视 Worker 的 CPU 和内存限制
  4. 未针对用例使用合适的存储
  5. 忘记 KV 的最终一致性
  6. 未实施恰当的速率限制
  7. 在代码中硬编码密钥
  8. 忽视冷启动优化

评论

支持 Markdown