Cloudflare Workers 最佳实践

Cloudflare Workers 最佳实践

☁️ Cloudflare Workers 最佳实践

基于生产环境模式、Cloudflare 内部使用以及开发者社区常见问题总结的 Workers 最佳实践。

📋 配置

保持兼容性日期为最新

compatibility_date 控制你的 Worker 可以使用哪些运行时功能和错误修复。在新项目中将其设置为今天的日期可确保你获得最新的行为。在现有项目中定期更新它,无需更改代码即可获得新的 API 和修复。

// wrangler.jsonc
{
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2026-02-16",
  "compatibility_flags": ["nodejs_compat"],
}

启用 nodejs_compat

nodejs_compat 兼容性标志让你的 Worker 可以访问 Node.js 内置模块,如 node:cryptonode:buffernode:stream 等。许多库依赖这些模块,启用此标志可避免运行时出现神秘的导入错误。

使用 wrangler types 生成绑定类型

不要手写 Env 接口。运行 wrangler types 生成与你的实际 Wrangler 配置匹配的类型定义文件。

wrangler types
✅ 良好

Env 由 wrangler types 生成,始终与你的配置匹配。不要手动定义 Env —— 它会与实际绑定产生偏差。

使用 wrangler secret 存储密钥

密钥(API 密钥、令牌、数据库凭证)绝不能出现在你的 Wrangler 配置或源代码中。

# 安全地存储密钥
wrangler secret put API_KEY

# 对于本地开发,使用 .env(确保它在 .gitignore 中)
# API_KEY=sk-test-abc123
🔴 错误

永远不要在 wrangler.jsonc 或 wrangler.toml 中放置密钥

正确设置自定义域名或路由

  • 自定义域名:Worker 是源站,Cloudflare 自动创建 DNS 记录和 SSL 证书
  • 路由:Worker 在现有源站服务器前面运行,需要代理 DNS 记录

🔄 请求和响应处理

流式传输请求和响应体

无论内存限制如何,流式传输大型请求和响应都是最佳实践。它可以减少峰值内存使用并改善首字节时间。

🔴 错误
// 将整个响应体缓冲到内存中
const badHandler = {
  async fetch(request, env) {
    const response = await fetch("https://api.example.com/large-dataset");
    const text = await response.text(); // ❌ 会崩溃
    return new Response(text);
  },
};
✅ 良好
// 流式传输响应体而不缓冲
export default {
  async fetch(request, env) {
    const response = await fetch("https://api.example.com/large-dataset");
    return new Response(response.body, response); // ✅ 流式传输
  },
};

使用 waitUntil 在响应后执行工作

ctx.waitUntil() 允许你在响应发送到客户端后执行工作,例如分析、缓存写入、非关键日志记录。

🔴 错误

解构 ctx 会丢失 this 绑定,抛出 "Illegal invocation" 错误

✅ 良好
export default {
  async fetch(request, env, ctx) {
    const data = await processRequest(request);
    
    ctx.waitUntil(logToAnalytics(env, data));
    ctx.waitUntil(updateCache(env, data));
    
    return Response.json(data);
  },
};

🏗️ 架构

使用绑定访问 Cloudflare 服务

不要使用 REST API,直接使用绑定(R2、KV、D1、Queues、Workflows)。

✅ 良好
// 直接使用绑定 —— 无需网络跳转,无需身份验证
export default {
  async fetch(request, env) {
    const object = await env.MY_BUCKET.get("my-file");
    if (!object) {
      return new Response("Not found", { status: 404 });
    }
    return new Response(object.body, {
      headers: { "Content-Type": object.httpMetadata?.contentType }
    });
  },
};

使用 Queues 和 Workflows 处理后台工作

  • 使用 Queues 当 你需要将生产者与消费者解耦,处理单步后台作业
  • 使用 Workflows 当 后台工作有多个相互依赖的步骤,需要持久化执行

使用 Hyperdrive 连接外部数据库

从 Worker 连接到远程 PostgreSQL 或 MySQL 数据库时,始终使用 Hyperdrive。它维护区域连接池,消除 TCP 握手、TLS 协商成本。

使用 Durable Objects 处理 WebSockets

对于可靠、长期的 WebSocket 连接,使用带有休眠 API 的 Durable Objects。

📊 可观测性

启用 Workers Logs 和 Traces

在部署到生产环境之前启用日志和追踪。使用结构化 JSON 日志记录。

✅ 良好
// 结构化 JSON —— 可搜索和可过滤
console.log(
  JSON.stringify({
    message: "incoming request",
    method: request.method,
    path: url.pathname,
  })
);

// console.error 显示为 "error" 严重性
console.error(
  JSON.stringify({
    message: "request failed",
    error: e.message,
  })
);
🔴 错误

非结构化字符串日志难以查询:console.log("Got a request to " + url.pathname)

💻 代码模式

不要在全局作用域中存储请求作用域状态

Workers 在请求之间重用 isolates。全局变量会导致跨请求数据泄漏。

✅ 良好

通过函数参数传递请求范围的数据

始终 await 或 waitUntil 你的 Promises

浮动 promise 会导致静默 bug:丢失结果、吞下错误和未完成的工作。

🔒 安全

使用 Web Crypto 生成安全令牌

🔴 错误

Math.random() 是可预测的,不适合安全用途

✅ 良好
// 加密安全的随机 UUID
const sessionId = crypto.randomUUID();

// 加密安全的随机字节用于令牌
const tokenBytes = new Uint8Array(32);
crypto.getRandomValues(tokenBytes);

不要使用 passThroughOnException 作为错误处理

使用显式 try/catch 块与结构化错误响应代替。

🧪 开发和测试

使用 @cloudflare/vitest-pool-workers 进行测试

在 Workers 运行时内运行你的测试,获得真实的绑定访问。

# ESLint 启用 no-floating-promises 规则
npx eslint --rule '{"@typescript-eslint/no-floating-promises": "error"}' src/

📚 相关资源


原文来源:Cloudflare Workers Best Practices

评论

此博客中的热门博文

最新版本BPB部署基础教程|百分百成功|利用 Cloudflare & BPB Panel |告别1101报错、节点泄露!

免费域名轻松Get!HIDNS 域名注册及使用保姆级教程(含 .CO & .VIP 优惠码)

免费白嫖 1 年的 Gemini Advanced 高级套餐!+ 免费获取美国Edu教育邮箱