workers-best-practices Skill:按生产约定审查和编写 Cloudflare Workers

前言

写 Cloudflare Workers 时,代码表面上很像普通 TypeScript:一个 fetch 处理器、几次 await、再 return new Response(...)。真正上线之后,问题往往出在运行时约定上,而不是语法。对未知大小的响应体 await response.text(),会把 Worker 的内存打满;模块顶层用 let 缓存当前用户,下一请求还能看见;随手写一个没有 awaitfetch(),isolate 可能在 Promise 跑完前就被回收。这些写法在 Node.js 服务里常常只是「不太优雅」,在 Workers 里会变成串数据、吞错误,或者直接崩溃。

另一边,团队里的 PR Review 也很容易变成同一张清单的重复劳动:compatibility_date 是不是太旧、密钥有没有写进 varsEnv 是手写的还是 wrangler types 生成的、有没有开 observability。AI 编程助手如果只靠训练数据,更容易把 Node.js 习惯搬到边缘上,给出过时的绑定类型或已经不推荐的配置字段。

Cloudflare 官方在 cloudflare/skills 仓库里维护了一条专项 Skill,名字就叫 workers-best-practices。它做的不是再讲一遍 Workers 入门,而是把「先查现行文档,再按清单写代码 / 审代码」收成 Agent 可执行的工作流,覆盖流式处理、floating promise、全局状态、密钥、绑定和 wrangler 配置。

这是什么

workers-best-practices 是 Cloudflare 官方出品的 Agent Skill,目录在:

https://github.com/cloudflare/skills/tree/main/skills/workers-best-practices

SKILL.md 头部的定位很直接:按生产最佳实践审查与编写 Cloudflare Workers 代码;在写新 Worker、审查已有代码、配置 wrangler.jsonc,或检查常见反模式(streaming、floating promises、global state、secrets、bindings、observability)时加载。同时写明:偏向从 Cloudflare 文档检索,而不是依赖模型的预训练知识

它要解决的是两件很具体的事:

  1. Workers 的坑和 Node.js 看起来一样,运行时行为却不一样。Agent 若按通用后端经验写,会漏掉 isolate 复用、内存上限、ctx 绑定这些约束。
  2. API 签名、兼容日期和 wrangler 字段会变。Skill 要求审查或生成代码之前,先拉现行最佳实践页、@cloudflare/workers-types 和本地 config-schema.json

同一仓库里还有总索引 Skill cloudflare、偏有状态协调的 durable-objects,以及偏 CLI 与资源管理的 wrangler。任务已经收敛到「写 Worker / 审 Worker / 查 wrangler 配置是否符合现行约定」时,应走 workers-best-practices 这一条。

Skill 目录是入口加两份按需参考:

skills/workers-best-practices/
├── SKILL.md
└── references/
    ├── rules.md    # 规则、正确写法与反模式
    └── review.md   # 类型检查、配置校验、绑定访问、审查流程

正文要求动手前先取现行资料,而不是把参考文件当最终 API 手册:

来源 怎么取 用来干什么
Workers 最佳实践 拉取 https://developers.cloudflare.com/workers/best-practices/workers-best-practices/ 规则、模式、反模式
Workers 类型 references/review.md API 签名、handler、绑定类型
Wrangler schema node_modules/wrangler/config-schema.json 配置字段、绑定形状、允许值
Cloudflare 文档 搜索或 https://developers.cloudflare.com/workers/ API、兼容日期与 flag

项目 node_modules 里的类型包如果偏旧,Skill 要求优先用最新发布版本。取类型的命令写在入口文件里:

mkdir -p /tmp/workers-types-latest && \
  npm pack @cloudflare/workers-types --pack-destination /tmp/workers-types-latest && \
  tar -xzf /tmp/workers-types-latest/cloudflare-workers-types-*.tgz -C /tmp/workers-types-latest
# Types at /tmp/workers-types-latest/package/index.d.ts

核心能力

Skill 把规则收成配置、请求响应、架构、可观测性、代码模式、安全几类,细节在 references/rules.md。下面按官方清单说明 Agent 加载之后应当检查什么。

1、配置:日期、兼容、类型和密钥

新项目要把 compatibility_date 设成当天日期,已有项目定期更新。nodejs_compat 要打开,很多库依赖 node:cryptonode:buffernode:stream,缺了这个 flag,运行时的 import 错误会很难看懂。绑定类型不要手写 interface Env,用 wrangler types 从配置生成,加绑定或改名之后再跑一次。密钥走 wrangler secret put,不要写进配置或源码;非密钥配置放 vars。新项目优先 wrangler.jsonc,Skill 写明较新的功能是 JSON-only,JSONC 还可以给配置决策加注释。

最小形态接近下面这样:

{
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2026-08-16",
  "compatibility_flags": ["nodejs_compat"],
  "vars": {
    "API_BASE_URL": "https://api.example.com"
  }
  // Secrets set via: wrangler secret put API_KEY
}

compatibility_date 应换成运行当天的日期。官方最佳实践页上的示例日期会随文档更新,不要把它抄成固定值。

生成类型:

npx wrangler types

放入密钥:

npx wrangler secret put API_KEY

对应的代码侧,Skill 推荐用生成出来的 Env,并用 satisfies ExportedHandler<Env> 校验导出,而不是自己维护一份绑定接口:

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const value = await env.MY_KV.get("key");
    return new Response(value);
  },
} satisfies ExportedHandler<Env>;

2、请求响应:流式,以及响应后的工作

Workers 有 128 MB 内存上限。对可能很大、长度未知的数据调用 await response.text()await response.json()await response.arrayBuffer(),会把整个 body 读进内存。已知大小、有界的 JSON 可以缓冲;大文件或上游大数据集应把 response.body 直接传下去,或用 TransformStream 管道。官方文档和 Skill 给的正确写法是同一类:

async fetch(request: Request, env: Env): Promise<Response> {
  const response = await fetch("https://api.example.com/large-dataset");
  return new Response(response.body, response);
}

响应已经可以返回、但还有分析、写缓存、打 webhook 这类收尾工作时,用 ctx.waitUntil(),不要把它们 await 在返回之前。Skill 和官方文档都强调:不要解构 ctxconst { waitUntil } = ctx 会丢掉 this,运行时抛 Illegal invocationwaitUntil 在响应发出后大约有 30 秒窗口,具体以现行文档为准。

3、架构:绑定优先,后台工作离开热路径

KV、R2、D1、Queues、Workflows 应走进程内绑定,不要在 Worker 里再调 https://api.cloudflare.com/client/v4/...。Worker 之间用 service binding(RPC 或 env.SERVICE.fetch()),不要走公网 URL。外部 PostgreSQL / MySQL 走 Hyperdrive,并且每个请求 new Client(),连接池由 Hyperdrive 管;这一条依赖 nodejs_compat

长任务、可重试任务、不挡响应的任务,从 fetch 热路径挪到 Queues 或 Workflows:

  • Queues:解耦生产与消费,扇出、缓冲、单步后台任务,至少一次投递。
  • Workflows:多步持久执行,每步返回值会落盘,失败只重试失败的那一步,可以跑很久。

Workflow 的专项规则不在这条 Skill 里,入口指向 Rules of Workflows

4、可观测性与代码模式

上生产前在 wrangler 配置里打开 observability,用 head_sampling_rate 控制日志和 trace 的量。日志用结构化 JSON,console.error 才会在控制台里落到 error 级别。

{
  "observability": {
    "enabled": true,
    "logs": { "head_sampling_rate": 1 },
    "traces": { "enabled": true, "head_sampling_rate": 0.01 }
  }
}
console.log(JSON.stringify({
  message: "incoming request",
  method: request.method,
  path: url.pathname,
}));

代码模式里有两条几乎每次审查都会碰到:

  1. 不要把请求态放进模块全局。 isolate 会跨请求复用,模块级 let currentUser 会造成串数据、过期状态,以及 Cannot perform I/O on behalf of a different request
  2. 每个 Promise 都要有归属。 需要结果就 awaitreturn;不挡响应就交给 ctx.waitUntil();也可以显式 void。裸 fetch() 是 floating promise:结果丢掉、错误被吞,isolate 还可能提前结束。Skill 要求用 @typescript-eslint/no-floating-promises 或 oxlint 的同类规则扫一遍。

5、安全,以及一张反模式表

安全相关的检查很具体:令牌和 ID 用 crypto.randomUUID() / crypto.getRandomValues(),不要用 Math.random();比较密钥用 crypto.subtle.timingSafeEqual(),先哈希到固定长度,避免按长度短路径返回。出错时显式 try/catch 并返回结构化错误,不要把 ctx.passThroughOnException() 当成错误处理——它会在 Worker 抛错时把请求交给源站,把 bug 藏起来。

SKILL.md 里的反模式表,是审查时真正会逐条打的清单。和官方最佳实践页能对上的包括:

反模式 为什么要紧
对无界数据 await response.text() 内存打满,128 MB 上限
源码或配置里写死密钥 进版本库就泄漏
Math.random() 当令牌 / ID 可预测,不是密码学安全
fetch()await 也不 waitUntil floating promise
模块级可变变量保存请求态 跨请求串数据
Worker 内调 Cloudflare REST API 多余网络跳、鉴权和延迟
ctx.passThroughOnException() 当错误处理 藏 bug
手写 Env 和真实绑定漂移
密钥用 === 比较 时序侧信道
解构 ctx Illegal invocation
Env 或 handler 参数写成 any 绑定访问失去类型
as unknown as T 把不兼容藏起来
对平台基类用 implements 而不是 extends 丢掉 this.ctx / this.env
平台基类里写 env.X 类里应是 this.env.X

references/review.md 还补了序列化边界:Queue 消息、Workflow 步骤返回值、Durable Object 存储、postMessage() 必须能 structured clone。ResponseError、带方法的类实例、Map / Set 看起来能编译,运行时会失败。

安装与启用

官方 README 写明:这套 Skill 面向支持 Agent Skills 标准的助手,包括 Claude Code、Cursor、OpenCode、OpenAI Codex 和 Pi。安装方式按工具分开,不要混用。

需要如实说一句:仓库 README 的 Skills 表目前列了 cloudflaredurable-objectswrangler 等,没有单独列出 workers-best-practices。GitHub 上 skills/ 目录里这条是存在的,YAML 描述也会在「审查 Worker / 写 wrangler.jsonc / 查反模式」时被自动加载。装整套集合就会带上它;只装这一条时,用下面带 --skill 的命令。

1、用 npx skills(跨工具通用)

安装整个 Cloudflare Skills 集合:

npx skills add https://github.com/cloudflare/skills

只装这一条时,officialskills.sh 上的页面skills.sh 给出的命令是:

npx skills add https://github.com/cloudflare/skills --skill workers-best-practices

2、Claude Code(插件市场)

/plugin marketplace add cloudflare/skills
/plugin install cloudflare@cloudflare

3、Cursor

仓库 README 的写法是:从 Cursor Marketplace 安装,或在 Settings > Rules > Add Rule > Remote Rule (Github) 里填 cloudflare/skills。Cloudflare 的 Cursor 接入文档 另外给出斜杠命令 /add-plugin cloudflare,效果是装上整套 Cloudflare Skills 并注册 MCP。

4、克隆后按目录拷贝

工具 Skill 目录
Claude Code ~/.claude/skills/
Cursor ~/.cursor/skills/
OpenCode ~/.config/opencode/skills/
OpenAI Codex ~/.codex/skills/
Pi ~/.pi/agent/skills/

拷进去的应是 skills/workers-best-practices/ 这一整个文件夹,保证 SKILL.mdreferences/ 的相对路径还在。OpenAI 的 openai/plugins 仓库里也有一份同名 SKILL.md,内容和 Cloudflare 官方仓库一致,Codex 用户可能会从那边拿到。

Agent 一般按描述自动启用。提示词里出现「审查这段 Worker」「检查 floating promise」「帮我看 wrangler.jsonc」「这段代码有没有把请求态放全局」时,就会对上这条 Skill。

典型用法

下面几段都来自官方 SKILL.md 和两份参考文件,用来说明 Agent 加载之后应当怎么工作,而不是另编一套 Workers 教程。

1、先检索,再按清单审一整份文件

Skill 给的审查流程是固定的,顺序不要颠倒:

  1. Retrieve:拉最新最佳实践页、workers types、wrangler schema
  2. Read full files:不要只看 diff,绑定访问模式要看完整文件
  3. Check types:绑定访问、handler 签名、禁止 any 和不安全断言
  4. Check configcompatibility_datenodejs_compat、observability、secrets、绑定与代码是否同名
  5. Check patterns:streaming、floating promises、全局状态、序列化边界
  6. Check security:Web Crypto、密钥、时序安全比较、错误处理
  7. Validate with toolsnpx tsc --noEmit,以及 no-floating-promises lint
  8. Reference rules:每条意见对照 references/rules.md 的正确写法

可以直接把触发条件写进提示词:

请按 workers-best-practices Skill 审查这个 Worker
先拉取 Cloudflare Workers 现行最佳实践页、@cloudflare/workers-types  wrangler  config-schema.json不要只靠训练数据
重点看无界 body 有没有被 text()/arrayBuffer() 整包读入有没有 floating promise模块全局有没有请求态密钥有没有进源码Env 是不是 wrangler types 生成的ctx 有没有被解构
读完整文件不要只看 diff给出文件名行号和依据

适合这条提示词的场景,和 Skill 自己的描述是对齐的:审 Worker PR、给把数据缓存在模块全局的代码做重构、核对 wrangler.jsonc 的绑定与可观测性、写新 Worker 时按现行约定落地。

2、审查意见的输出格式

references/review.md 要求意见带证据,不要只给「建议改进」这类空话:

**[SEVERITY]** Brief description
`file.ts:42`  explanation with evidence
Suggested fix: `code`

级别是 CRITICAL(安全、丢数据、崩溃)、HIGH(类型错误、错误 API、坏掉的配置)、MEDIUM(缺校验、边界情况)、LOW(风格、小改进)。Skill 自己的原则也写在入口里:先检索再下结论;引用行号、工具输出或文档链接;例子以开发者会复制进生产的那段为准;正确比面面俱到更重要。

3、几段会反复出现的对照代码

全局请求态,错误写法和正确写法:

// 反模式:模块级可变状态,请求之间会泄漏
let currentUser: string | null = null;

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    currentUser = request.headers.get("X-User-Id");
    // ...
  },
};
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const userId = request.headers.get("X-User-Id");
    const result = await handleRequest(userId, env);
    return Response.json(result);
  },
} satisfies ExportedHandler<Env>;

响应后的收尾工作:

async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
  const data = await processRequest(request);

  ctx.waitUntil(logToAnalytics(env, data));
  ctx.waitUntil(updateCache(env, data));

  return Response.json(data);
}

绑定代替 REST:

const object = await env.MY_BUCKET.get("my-file");

工具校验,Skill 原文给出的命令是:

npx tsc --noEmit

npx eslint --rule '{"@typescript-eslint/no-floating-promises": "error"}' src/

npx oxlint --deny typescript/no-floating-promises src/

4、测试时不要被 Vitest 的自动注入骗过

rules.md 和官方最佳实践页都写了同一条坑:用 @cloudflare/vitest-pool-workers 可以在 Workers 运行时里测真实绑定,这是推荐做法;但这个 pool 会自动注入 nodejs_compat,所以测试能过,并不代表 wrangler.jsonc 里已经开了这个 flag。代码若依赖 Node.js 内置模块,配置里仍要显式写上。

适用场景与注意事项

比较适合这条 Skill 的情况:

  1. 正在写或重构 Cloudflare Workers,希望生成结果符合现行生产约定,而不是一份「能跑的 Node 风格代码」。
  2. 给 Worker PR 做审查,尤其是反复出现 floating promise、全局状态、密钥和 wrangler 配置问题的仓库。
  3. 要核对 wrangler.jsonc 与代码里的绑定名、类型、observability 是否一致。
  4. 团队想把 Workers 特有的反模式固化成 Agent 可执行清单,减少同一类 Review 评论。

不太适合、或需要换 Skill 的情况,入口文件的 Scope 写得很清楚:

  1. Durable Objects:加载同仓的 durable-objects
  2. Workflows:看 Rules of Workflows,不要把这条 Skill 当成 Workflow 手册。
  3. Wrangler CLI 命令(部署、建 KV/R2/D1 资源):加载 wrangler
  4. 产品选型和全平台导航:用同仓的 cloudflare
  5. 这条 Skill 是给编码助手的工作流,不会替你开通账号,也不包含计费决策。

使用时几条已经能交叉核实的约束,值得写进提示词:

  • 先检索再下结论。 入口第一句就是:你对 Workers API、类型和配置的知识可能过时。
  • 读完整文件。 绑定是 env.X 还是 this.env.X,只看 diff 经常看不出来。
  • 平台基类用 extends DurableObjectWorkerEntrypointWorkflow 上写 implements 是旧模式。
  • CPU 和内存数字以现行文档为准。 Skill 会提醒去 /workers/platform/limits/ 核对;内存 128 MB 这一条目前和官方最佳实践页一致,计划档位的 CPU 限额不要死记。
  • Vitest 通过不等于配置正确。 确认 wrangler.jsonc 里真的有 nodejs_compat
  • README 表格不是完整目录。 装集合或按路径拷贝时,以 skills/workers-best-practices/ 是否存在为准。

小结

workers-best-practices 这条 Skill 的价值,不在于把 Workers 文档再复制一遍,而在于把一张会过时的审查清单,收成 Agent 每次写代码、审 PR 时都要走的流程:先拉现行文档和类型,再核对配置、流式处理、Promise 归属、全局状态、密钥和可观测性。Cloudflare 把边缘运行时的坑写成反模式表之后,重复出现在 Review 里的那些评论,就可以交给会读 SKILL.md 的助手去打第一遍。

官方目录:https://github.com/cloudflare/skills/tree/main/skills/workers-best-practices

仓库说明与各工具安装方式:https://github.com/cloudflare/skills

最佳实践正文:https://developers.cloudflare.com/workers/best-practices/workers-best-practices/

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜