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/

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

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

小夜