cloudflare-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloudflare Development Best Practices
Cloudflare开发最佳实践
Overview
概述
This skill provides comprehensive guidelines for developing applications on Cloudflare's edge platform, including Workers, Pages, KV storage, D1 databases, R2 object storage, and Durable Objects.
本指南提供了在Cloudflare边缘平台上开发应用的全面准则,涵盖Workers、Pages、KV存储、D1数据库、R2对象存储及Durable Objects。
Core Principles
核心原则
- Write lightweight, fast code optimized for edge execution
- Minimize cold start times and execution duration
- Use appropriate storage solutions for each use case
- Follow security best practices for edge computing
- Leverage Cloudflare's global network for performance
- 编写轻量、快速的代码,针对边缘执行进行优化
- 最小化冷启动时间和执行时长
- 为不同使用场景选择合适的存储方案
- 遵循边缘计算的安全最佳实践
- 利用Cloudflare全球网络提升性能
Cloudflare Workers Guidelines
Cloudflare Workers指南
Basic Worker Structure
基础Worker结构
typescript
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>;typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
try {
const url = new URL(request.url);
// 路由处理
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>;Environment Types
环境类型
typescript
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
interface Env {
// KV命名空间
MY_KV: KVNamespace;
// D1数据库
MY_DB: D1Database;
// R2存储桶
MY_BUCKET: R2Bucket;
// Durable Objects
MY_DURABLE_OBJECT: DurableObjectNamespace;
// 环境变量
API_KEY: string;
}Best Practices
最佳实践
- Use TypeScript for type safety
- Handle errors at the edge appropriately
- Implement proper request validation
- Use for background tasks
ctx.waitUntil() - Minimize external API calls when possible
- 使用TypeScript保证类型安全
- 在边缘端妥善处理错误
- 实现恰当的请求验证
- 使用处理后台任务
ctx.waitUntil() - 尽可能减少外部API调用
Wrangler Configuration
Wrangler配置
wrangler.toml Structure
wrangler.toml结构
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"]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 Storage Guidelines
KV存储指南
Usage Patterns
使用模式
typescript
// 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:' });typescript
// 写入KV
await env.MY_KV.put('key', JSON.stringify(data), {
expirationTtl: 3600, // 1小时
metadata: { version: '1.0' },
});
// 读取KV
const value = await env.MY_KV.get('key', { type: 'json' });
// 列出键
const list = await env.MY_KV.list({ prefix: 'user:' });Best Practices
最佳实践
- Use KV for read-heavy workloads with eventual consistency
- Set appropriate TTLs for cached data
- Use metadata for additional key information
- Implement cache invalidation strategies
- Be aware of KV's eventual consistency model
- 将KV用于读密集型、最终一致性的工作负载
- 为缓存数据设置合适的TTL
- 使用元数据存储额外的键信息
- 实现缓存失效策略
- 注意KV的最终一致性模型
D1 Database Guidelines
D1数据库指南
Query Patterns
查询模式
typescript
// 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();typescript
// 参数化查询(防止SQL注入)
const results = await env.MY_DB
.prepare('SELECT * FROM users WHERE id = ?')
.bind(userId)
.all();
// 批量操作
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'),
]);
// 仅获取第一条结果
const user = await env.MY_DB
.prepare('SELECT * FROM users WHERE email = ?')
.bind(email)
.first();Schema Management
架构管理
sql
-- 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);sql
-- 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);Best Practices
最佳实践
- Always use parameterized queries
- Create appropriate indexes
- Use batch operations for multiple writes
- Keep queries simple and efficient
- Use migrations for schema changes
- 始终使用参数化查询
- 创建合适的索引
- 对多次写入操作使用批量处理
- 保持查询简洁高效
- 使用迁移来管理架构变更
R2 Object Storage Guidelines
R2对象存储指南
Usage Patterns
使用模式
typescript
// 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');typescript
// 上传对象
await env.MY_BUCKET.put('uploads/file.pdf', fileData, {
httpMetadata: {
contentType: 'application/pdf',
},
customMetadata: {
uploadedBy: userId,
},
});
// 下载对象
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',
},
});
}
// 列出对象
const list = await env.MY_BUCKET.list({ prefix: 'uploads/' });
// 删除对象
await env.MY_BUCKET.delete('uploads/file.pdf');Best Practices
最佳实践
- Set appropriate content types
- Use multipart uploads for large files
- Implement proper access controls
- Use presigned URLs for direct client uploads
- Organize objects with logical prefixes
- 设置合适的内容类型
- 对大文件使用分段上传
- 实现恰当的访问控制
- 使用预签名URL支持客户端直接上传
- 用逻辑前缀组织对象
Durable Objects Guidelines
Durable Objects指南
Implementation
实现示例
typescript
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);
});
}
}typescript
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) => {
// 处理消息
});
webSocket.addEventListener('close', () => {
this.sessions.delete(webSocket);
});
}
}Best Practices
最佳实践
- Use for coordination and stateful logic
- Implement proper WebSocket handling
- Use storage API for persistence
- Handle hibernation for cost optimization
- Design for single-point-of-coordination patterns
- 用于协调和有状态逻辑场景
- 实现恰当的WebSocket处理
- 使用存储API实现持久化
- 利用休眠机制优化成本
- 设计单点协调模式
Cloudflare Pages Guidelines
Cloudflare Pages指南
Project Structure
项目结构
my-pages-project/
├── public/ # Static assets
├── functions/ # Pages Functions
│ ├── api/
│ │ └── [endpoint].ts
│ └── _middleware.ts
├── src/ # Application source
└── wrangler.toml # Configurationmy-pages-project/
├── public/ # 静态资源
├── functions/ # Pages Functions
│ ├── api/
│ │ └── [endpoint].ts
│ └── _middleware.ts
├── src/ # 应用源码
└── wrangler.toml # 配置文件Pages Functions
Pages Functions示例
typescript
// 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 });
};typescript
// 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();
// 处理POST请求
return Response.json({ success: true });
};Edge Security Best Practices
边缘安全最佳实践
Request Validation
请求验证
typescript
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;
}typescript
function validateRequest(request: Request): boolean {
// 检查内容类型
const contentType = request.headers.get('Content-Type');
if (request.method === 'POST' && !contentType?.includes('application/json')) {
return false;
}
// 检查来源(CORS)
const origin = request.headers.get('Origin');
if (origin && !ALLOWED_ORIGINS.includes(origin)) {
return false;
}
return true;
}Authentication
身份验证
typescript
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);
}typescript
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);
// 验证JWT或API密钥
return await verifyToken(token, env);
}Rate Limiting
请求限流
typescript
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;
}typescript
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次请求
return false;
}
await env.MY_KV.put(key, JSON.stringify(current + 1), {
expirationTtl: 60, // 1分钟窗口
});
return true;
}Performance Optimization
性能优化
Caching Strategies
缓存策略
typescript
// 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;
}typescript
// 使用Cache API
const cache = caches.default;
async function handleRequest(request: Request): Promise<Response> {
// 检查缓存
const cached = await cache.match(request);
if (cached) {
return cached;
}
// 生成响应
const response = await generateResponse(request);
// 缓存响应
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;
}Background Processing
后台处理
typescript
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;
},
};typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
// 立即返回响应
const response = Response.json({ status: 'accepted' });
// 在后台处理任务
ctx.waitUntil(processInBackground(request, env));
return response;
},
};Testing
测试
Local Development
本地开发
bash
undefinedbash
undefinedStart local development server
启动本地开发服务器
wrangler dev
wrangler dev
Run with local persistence
启用本地持久化
wrangler dev --persist
wrangler dev --persist
Test with specific environment
使用指定环境测试
wrangler dev --env staging
undefinedwrangler dev --env staging
undefinedUnit Testing
单元测试
typescript
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);
});
});typescript
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('有效请求返回200状态码', async () => {
const response = await worker.fetch('/api/health');
expect(response.status).toBe(200);
});
});Deployment
部署
Production Deployment
生产环境部署
bash
undefinedbash
undefinedDeploy to production
部署到生产环境
wrangler deploy
wrangler deploy
Deploy to specific environment
部署到指定环境
wrangler deploy --env production
wrangler deploy --env production
Deploy with secrets
部署时配置密钥
wrangler secret put API_KEY
undefinedwrangler secret put API_KEY
undefinedCI/CD Integration
CI/CD集成
yaml
undefinedyaml
undefined.github/workflows/deploy.yml
.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 }}
undefinedname: 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 }}
undefinedCommon Pitfalls to Avoid
需避免的常见陷阱
- Not handling errors at the edge properly
- Making too many external API calls
- Ignoring Worker CPU and memory limits
- Not using appropriate storage for use case
- Forgetting eventual consistency in KV
- Not implementing proper rate limiting
- Hardcoding secrets in code
- Ignoring cold start optimization
- 未在边缘端妥善处理错误
- 发起过多外部API调用
- 忽略Worker的CPU和内存限制
- 未为使用场景选择合适的存储方案
- 忘记KV的最终一致性特性
- 未实现恰当的请求限流
- 在代码中硬编码密钥
- 忽略冷启动优化