一、为什么选择 Cloudflare Workers 在 Serverless 架构百花齐放的今天,Cloudflare Workers 凭借其独特的优势脱颖而出。不同于 AWS Lambda 的冷启动延迟(通常在 200ms-2s),Workers 基于 V8 Isolate 技术,冷启动时间低于 5ms,几乎可以忽略不计。
1.1 核心优势
全球 300+ 节点 :用户请求自动路由到最近节点,延迟极低
免费额度慷慨 :每天 10 万次请求,个人项目完全够用
生态完善 :KV、D1、R2、Durable Objects、Queues 等存储方案一应俱全
开发体验好 :Wrangler CLI 一键部署,支持本地调试
1.2 适用场景 Workers 并非银弹,以下场景特别适合:
API 网关和 BFF 层
静态网站的动态功能扩展(如评论系统、表单处理)
反向代理和 A/B 测试
定时任务(Cron Triggers)
Webhook 处理
不适合的场景:
长时间运行的任务(CPU 时间限制 10ms-30s)
大量计算密集型任务
需要传统文件系统的应用
二、项目结构与配置最佳实践 2.1 目录结构 一个规范的 Workers 项目应该这样组织:
1 2 3 4 5 6 7 8 9 10 11 12 13 my-worker/ ├── src/ │ ├── index.js # 入口文件 │ ├── router.js # 路由处理 │ ├── handlers/ # 请求处理器 │ │ ├── api.js │ │ └── webhook.js │ └── utils/ # 工具函数 │ ├── auth.js │ └── response.js ├── wrangler.toml # 配置文件 ├── package.json └── .dev.vars # 本地环境变量(不提交)
2.2 wrangler.toml 配置详解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 name = "my-worker" main = "src/index.js" compatibility_date = "2025-08-01" account_id = "your-account-id" routes = [ { pattern = "api.example.com" , custom_domain = true } ] [[kv_namespaces]] binding = "MY_KV" id = "your-kv-id" [[d1_databases]] binding = "DB" database_name = "my-db" database_id = "your-d1-id" [[r2_buckets]] binding = "BUCKET" bucket_name = "my-bucket"
关键配置说明 :
compatibility_date:决定 API 行为,建议使用最新日期
custom_domain = true:使用自定义域名而非 workers.dev,国内访问更稳定
环境变量(Secret)不要写入配置文件,通过 wrangler secret put 设置
三、路由与请求处理 3.1 原生路由方案 Workers 没有内置路由,但可以用 URL API 轻松实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 export default { async fetch (request, env, ctx ) { const url = new URL (request.url ) const path = url.pathname if (path === '/api/health' && request.method === 'GET' ) { return new Response (JSON .stringify ({ ok : true }), { headers : { 'Content-Type' : 'application/json' } }) } if (path.startsWith ('/api/users/' ) && request.method === 'GET' ) { const userId = path.split ('/' )[3 ] return handleGetUser (userId, env) } return new Response ('Not Found' , { status : 404 }) } }
3.2 推荐:使用 itty-router 对于复杂项目,推荐使用 itty-router ,一个仅 400 字节的路由库:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import { Router } from 'itty-router' const router = Router ()router.get ('/api/health' , () => ({ ok : true })) router.get ('/api/users/:id' , ({ params } ) => { return { userId : params.id } }) router.post ('/api/users' , async (request) => { const body = await request.json () return { success : true } }) router.all ('*' , () => new Response ('Not Found' , { status : 404 })) export default { fetch : router.handle }
四、存储方案选择 4.1 KV:键值存储 KV 适合读多写少的场景,如配置缓存、会话存储:
1 2 3 4 5 6 7 8 9 10 await env.MY_KV .put ('user:123' , JSON .stringify (userData), { expirationTtl : 3600 }) const data = await env.MY_KV .get ('user:123' , 'json' )await env.MY_KV .delete ('user:123' )
注意事项 :
KV 是最终一致性,写入后可能有几秒延迟才能在全球节点读到
不适合频繁写入的场景(每秒最多 1 次写入 per key)
Value 最大 25MB
4.2 D1:SQLite 数据库 D1 是 Cloudflare 的原生 SQLite 数据库,适合需要复杂查询的场景:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const { results } = await env.DB .prepare ( 'SELECT id, name, email FROM users WHERE id = ?' ).bind (userId).all () const result = await env.DB .prepare ( 'INSERT INTO users (name, email) VALUES (?, ?)' ).bind (name, email).run () console .log ('插入ID:' , result.meta .last_row_id )await env.DB .batch ([ env.DB .prepare ('UPDATE accounts SET balance = balance - ? WHERE id = ?' ).bind (100 , fromId), env.DB .prepare ('UPDATE accounts SET balance = balance + ? WHERE id = ?' ).bind (100 , toId) ])
D1 最佳实践 :
使用参数化查询,避免 SQL 注入
批量操作用 batch(),减少网络往返
大表加索引,查询性能提升明显
定期备份(wrangler d1 export)
4.3 R2:对象存储 R2 是 S3 兼容的对象存储,零出口流量费:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 await env.BUCKET .put ('avatars/user-123.jpg' , imageBuffer, { httpMetadata : { contentType : 'image/jpeg' } }) const object = await env.BUCKET .get ('avatars/user-123.jpg' )if (object) { return new Response (object.body , { headers : { 'Content-Type' : object.httpMetadata .contentType } }) } await env.BUCKET .delete ('avatars/user-123.jpg' )
五、性能优化技巧 5.1 减少 CPU 时间 Workers 有 CPU 时间限制(免费计划每次请求 10ms),需要注意:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 export default { async fetch (request ) { const result = heavyComputation () return new Response (result) } } let cachedResult = null export default { async fetch (request ) { if (!cachedResult) { cachedResult = heavyComputation () } return new Response (cachedResult) } }
5.2 并行 IO 操作 多个独立的 IO 操作应该并行执行:
1 2 3 4 5 6 7 8 9 10 11 const user = await env.DB .prepare ('SELECT * FROM users WHERE id = ?' ).bind (id).first ()const posts = await env.DB .prepare ('SELECT * FROM posts WHERE user_id = ?' ).bind (id).all ()const comments = await env.DB .prepare ('SELECT * FROM comments WHERE user_id = ?' ).bind (id).all ()const [user, posts, comments] = await Promise .all ([ env.DB .prepare ('SELECT * FROM users WHERE id = ?' ).bind (id).first (), env.DB .prepare ('SELECT * FROM posts WHERE user_id = ?' ).bind (id).all (), env.DB .prepare ('SELECT * FROM comments WHERE user_id = ?' ).bind (id).all () ])
5.3 响应缓存 对于不常变化的内容,使用 Cache API 缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 export default { async fetch (request, env, ctx ) { const cache = caches.default const cachedResponse = await cache.match (request) if (cachedResponse) { return cachedResponse } const response = await generateResponse (request) response.headers .set ('Cache-Control' , 's-maxage=3600' ) ctx.waitUntil (cache.put (request, response.clone ())) return response } }
六、安全实践 6.1 CORS 处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const corsHeaders = { 'Access-Control-Allow-Origin' : 'https://your-domain.com' , '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 ) { if (request.method === 'OPTIONS' ) { return new Response (null , { headers : corsHeaders }) } const response = await handleRequest (request) Object .entries (corsHeaders).forEach (([k, v] ) => { response.headers .set (k, v) }) return response } }
6.2 请求频率限制 简单的 IP 限流:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const RATE_LIMIT = 100 const WINDOW = 60 export default { async fetch (request, env ) { const ip = request.headers .get ('CF-Connecting-IP' ) const key = `rate:${ip} ` const count = parseInt (await env.RATE_KV .get (key)) || 0 if (count >= RATE_LIMIT ) { return new Response ('Too Many Requests' , { status : 429 }) } await env.RATE_KV .put (key, String (count + 1 ), { expirationTtl : WINDOW }) return handleRequest (request) } }
七、调试与排错 7.1 本地开发 1 2 3 4 5 6 7 8 wrangler dev wrangler dev --remote wrangler tail
7.2 常见问题排查
问题
可能原因
解决方案
1015 错误
CPU 超时
优化计算逻辑,减少同步操作
1042 错误
内存超限
检查是否有内存泄漏,减少大对象
500 错误
未捕获异常
添加 try-catch,检查环境变量
KV 读取不到
最终一致性
写入后等待几秒,或使用 metadata
D1 查询慢
缺少索引
对常用查询字段加索引
八、部署与 CI/CD 8.1 手动部署 1 2 3 4 5 wrangler deploy wrangler deploy --env staging
8.2 GitHub Actions 自动部署 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 ci - name: Deploy uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
九、成本估算
资源
免费额度
超出价格
请求次数
10万/天
$0.50/百万次
CPU 时间
10ms/请求
$0.02/GB-s
KV 存储
1GB
$0.50/GB/月
KV 读取
10万/天
$0.50/百万次
D1 存储
5GB
$0.75/GB/月
D1 读取
500万行/天
$0.001/百万行
R2 存储
10GB
$0.015/GB/月
R2 操作
100万/月
$0.004/万次
对于个人项目,免费额度基本够用。即使超出,成本也很低。
十、总结 Cloudflare Workers 是一个强大的边缘计算平台,特别适合个人开发者和小型团队。通过本文介绍的最佳实践,你可以构建出高性能、低成本的 Serverless 应用。
核心要点回顾:
合理选择存储方案(KV/D1/R2)
优化 CPU 时间和 IO 操作
重视安全(CORS、限流、验证)
善用缓存提升性能
建立完善的 CI/CD 流程
希望这篇指南能帮助你更好地使用 Cloudflare Workers。如有问题,欢迎在评论区交流。