前言¶
寫 Cloudflare Workers 時,代碼表面上很像普通 TypeScript:一個 fetch 處理器、幾次 await、再 return new Response(...)。真正上線之後,問題往往出在運行時約定上,而不是語法。對未知大小的響應體 await response.text(),會把 Worker 的內存打滿;模塊頂層用 let 緩存當前用戶,下一請求還能看見;隨手寫一個沒有 await 的 fetch(),isolate 可能在 Promise 跑完前就被回收。這些寫法在 Node.js 服務裏常常只是「不太優雅」,在 Workers 裏會變成串數據、吞錯誤,或者直接崩潰。
另一邊,團隊裏的 PR Review 也很容易變成同一張清單的重複勞動:compatibility_date 是不是太舊、密鑰有沒有寫進 vars、Env 是手寫的還是 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 文檔檢索,而不是依賴模型的預訓練知識。
它要解決的是兩件很具體的事:
- Workers 的坑和 Node.js 看起來一樣,運行時行爲卻不一樣。Agent 若按通用後端經驗寫,會漏掉 isolate 複用、內存上限、
ctx綁定這些約束。 - 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:crypto、node:buffer、node: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 和官方文檔都強調:不要解構 ctx。const { waitUntil } = ctx 會丟掉 this,運行時拋 Illegal invocation。waitUntil 在響應發出後大約有 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,
}));
代碼模式裏有兩條几乎每次審查都會碰到:
- 不要把請求態放進模塊全局。 isolate 會跨請求複用,模塊級
let currentUser會造成串數據、過期狀態,以及Cannot perform I/O on behalf of a different request。 - 每個 Promise 都要有歸屬。 需要結果就
await或return;不擋響應就交給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。Response、Error、帶方法的類實例、Map / Set 看起來能編譯,運行時會失敗。
安裝與啓用¶
官方 README 寫明:這套 Skill 面向支持 Agent Skills 標準的助手,包括 Claude Code、Cursor、OpenCode、OpenAI Codex 和 Pi。安裝方式按工具分開,不要混用。
需要如實說一句:倉庫 README 的 Skills 表目前列了 cloudflare、durable-objects、wrangler 等,沒有單獨列出 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.md 和 references/ 的相對路徑還在。OpenAI 的 openai/plugins 倉庫裏也有一份同名 SKILL.md,內容和 Cloudflare 官方倉庫一致,Codex 用戶可能會從那邊拿到。
Agent 一般按描述自動啓用。提示詞裏出現「審查這段 Worker」「檢查 floating promise」「幫我看 wrangler.jsonc」「這段代碼有沒有把請求態放全局」時,就會對上這條 Skill。
典型用法¶
下面幾段都來自官方 SKILL.md 和兩份參考文件,用來說明 Agent 加載之後應當怎麼工作,而不是另編一套 Workers 教程。
1、先檢索,再按清單審一整份文件¶
Skill 給的審查流程是固定的,順序不要顛倒:
- Retrieve:拉最新最佳實踐頁、workers types、wrangler schema
- Read full files:不要只看 diff,綁定訪問模式要看完整文件
- Check types:綁定訪問、handler 簽名、禁止
any和不安全斷言 - Check config:
compatibility_date、nodejs_compat、observability、secrets、綁定與代碼是否同名 - Check patterns:streaming、floating promises、全局狀態、序列化邊界
- Check security:Web Crypto、密鑰、時序安全比較、錯誤處理
- Validate with tools:
npx tsc --noEmit,以及no-floating-promiseslint - 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 的情況:
- 正在寫或重構 Cloudflare Workers,希望生成結果符合現行生產約定,而不是一份「能跑的 Node 風格代碼」。
- 給 Worker PR 做審查,尤其是反覆出現 floating promise、全局狀態、密鑰和 wrangler 配置問題的倉庫。
- 要覈對
wrangler.jsonc與代碼裏的綁定名、類型、observability 是否一致。 - 團隊想把 Workers 特有的反模式固化成 Agent 可執行清單,減少同一類 Review 評論。
不太適合、或需要換 Skill 的情況,入口文件的 Scope 寫得很清楚:
- Durable Objects:加載同倉的
durable-objects。 - Workflows:看 Rules of Workflows,不要把這條 Skill 當成 Workflow 手冊。
- Wrangler CLI 命令(部署、建 KV/R2/D1 資源):加載
wrangler。 - 產品選型和全平臺導航:用同倉的
cloudflare。 - 這條 Skill 是給編碼助手的工作流,不會替你開通賬號,也不包含計費決策。
使用時幾條已經能交叉覈實的約束,值得寫進提示詞:
- 先檢索再下結論。 入口第一句就是:你對 Workers API、類型和配置的知識可能過時。
- 讀完整文件。 綁定是
env.X還是this.env.X,只看 diff 經常看不出來。 - 平臺基類用
extends。DurableObject、WorkerEntrypoint、Workflow上寫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/