跳到內容

課程大綱

版本基準:2026 年 7 月。所有 API、設定鍵名、產品狀態皆以此時間點的官方文件為準。 目標讀者:有經驗的全端開發者(熟 TypeScript / REST / SQL,但沒碰過 Cloudflare)。 結構:單一貫穿專案 + 各章獨立最小範例


假設會不假設會
TypeScript、ES modules、npm/pnpmCloudflare 任何產品
HTTP 語意、REST、JSONV8 isolate 執行模型
SQL(SELECT / JOIN / index)SQLite 的邊緣特性
Git、基本 CI 概念Wrangler / miniflare / workerd
Docker 基本操作Actor model / durable execution

每篇開頭固定標示「前置章節」,允許讀者跳讀。

每一篇文章都由三塊組成,比例大約 4:4:2:

  1. 心智模型(Why) — 這個 primitive 解決什麼問題、它的物理限制是什麼。對有經驗的開發者,這是最有價值的部分,也是 AI 生成內容最容易略過的部分。
  2. 獨立最小範例(How) — 一個 30–80 行、可以單獨 git clone 跑起來的 demo,不依賴貫穿專案。
  3. 貫穿專案進度(Real) — 把該章的 primitive 接進 LinkForge,處理真實世界的邊角:錯誤、重試、成本、多租戶隔離。
## 前置章節
## 這篇要解決的問題
## 心智模型
## 動手做:最小範例
## 接進 LinkForge
## 限制與計費(Limits & Pricing)
## 常見陷阱(Gotchas)
## 延伸閱讀

「限制與計費」與「常見陷阱」是本系列的差異化重點。Cloudflare 官方文件把 limits 放在獨立頁面,多數教學完全不提,導致讀者在 production 才踩雷。

  • 專業名詞一律保留英文:Durable Objectbindingisolateeventual consistencycold start。不翻譯成「持久物件」。
  • 程式碼、註解、檔名、commit message 一律英文。
  • 每個 code block 標註可執行的最小前置條件(wrangler 版本、compatibility date)。
  • 所有計費數字標註查證日期,並提醒讀者以官方 pricing 頁為準。

多租戶短網址 + 即時點擊分析平台。

選它的理由:短網址是極端讀多寫少天然多租戶天然事件流的工作負載,正好逐一逼出 Cloudflare 每個 primitive 的存在理由,而不是為了用而用。

┌─────────────────────────────┐
go.lnk.fo/abc ──▶ │ Worker: redirector │
│ KV lookup → 302 │──▶ Queue: click-events
└─────────────────────────────┘ │
app.lnk.fo ──▶ Worker: dashboard (React Router v8) Worker: click-consumer
│ │
├─ D1 (Drizzle) : tenants, links, users │├─▶ Analytics Engine
├─ Durable Object: LinkCounter (即時計數) │├─▶ D1 rollup
├─ Durable Object: LiveDashboard (WS) │└─▶ Pipelines → R2 (Iceberg)
├─ R2 : CSV/QR/OG image │
├─ Workflow : weekly report + email │
├─ Workers AI : 惡意連結掃描、摘要 │
└─ Vectorize : 連結語意搜尋
lnk.fo (行銷/文件) ──▶ Astro on Workers
PartLinkForge 進度
1可部署的 redirect Worker(硬編碼對照表)+ Hono API 骨架
2KV 熱路徑查詢 + D1/Drizzle 資料模型 + R2 匯出
3DO 即時計數器 + WebSocket 即時看板 + alarm 聚合
4Queue 點擊事件管線 + Analytics Engine 分析後台 + Workflow 週報
5React Router v8 管理後台 + Astro 行銷站 + 完整 auth
6自訂網域、OG 圖片自動截圖、寄信、多租戶隔離
7AI 惡意連結偵測 + 語意搜尋 + MCP server
8測試套件、observability、CI/CD、成本儀表板

2.3 Repo 結構(monorepo, pnpm workspace)

Section titled “2.3 Repo 結構(monorepo, pnpm workspace)”
linkforge/
├── apps/
│ ├── redirector/ # 熱路徑 Worker,刻意保持極簡
│ ├── api/ # Hono API + DO + Workflows
│ ├── dashboard/ # React Router v8 on Workers
│ ├── site/ # Astro on Workers
│ └── consumers/ # Queue consumer Worker
├── packages/
│ ├── db/ # Drizzle schema + migrations
│ ├── shared/ # 共用型別、zod schema
│ └── config/ # tsconfig / eslint 基底
└── examples/ # 各章獨立範例,ch03/ ch08/ ...

Part 0 — 心智模型與工具鏈(2 篇)

Section titled “Part 0 — 心智模型與工具鏈(2 篇)”

01. 為什麼是 Workers:isolate 不是「更快的 Lambda」

Section titled “01. 為什麼是 Workers:isolate 不是「更快的 Lambda」”
  • 學習目標:能說清楚 V8 isolate 與 container-based serverless 在冷啟動、記憶體、並行、計費上的根本差異,並判斷哪些工作負載不適合放上去。
  • 涵蓋:V8 isolate vs container/microVM;為什麼沒有傳統 cold start;每個 request 的 CPU time 而非 wall time 計費;nodejs_compat 的邊界(不是 Node.js,是實作了部分 Node API 的獨立 runtime);沒有檔案系統、沒有長駐 process、沒有 eval();Free 10ms CPU vs Paid 30s CPU 的設計含義。
  • 獨立範例:同一支 API 分別部署到 Workers 與一個傳統 Node 容器,量測 p50/p99 與冷啟動。
  • LinkForge:定義專案目標與非目標,說明哪些部分故意不放在 edge。
  • 陷阱:把 Workers 當 Node.js 用;以為 nodejs_compat 等於完整 Node;在全域作用域做 I/O。
  • 篇幅:~2,500 字,程式碼少。

02. 工具鏈:Wrangler v4、wrangler.jsonc 與本機開發

Section titled “02. 工具鏈:Wrangler v4、wrangler.jsonc 與本機開發”
  • 學習目標:建立一個 2026 年標準的 Worker 專案,理解 compatibility_date 的真正作用,並知道本機開發到底在跑什麼。
  • 涵蓋
    • npm create cloudflare@latestwrangler.jsonc 是新專案的建議格式(部分新功能只支援 JSON config),含 $schema
    • compatibility_date / compatibility_flags:為什麼日期會改變 runtime 行為;2026 年的 compat date 預設開啟遠多於 2024 年的 Node API。
    • wrangler types 產生 worker-configuration.d.ts取代手動安裝 @cloudflare/workers-types)。
    • 本機開發=真的 workerd(miniflare v4),不是模擬器。
    • Remote bindings:per-binding "remote": true,取代舊的 wrangler dev --remote
    • Wrangler v4 起 wrangler kv/d1/r2 指令預設操作本機,2024 年的教學指令複製過來會靜默地打錯目標。
  • 獨立範例:一個 Worker,vars + secret + 一個 remote KV binding,示範本機/遠端混合開發。
  • LinkForge:建立 monorepo 骨架、pnpm workspace、共用 tsconfig、cf-typegen script。
  • 陷阱(不要教)wrangler publishnode_compatusage_model[site] Workers Sites、Service Worker 語法(addEventListener('fetch'))、手動加 nodejs_compat_v2
  • 篇幅:~3,000 字。


03. 執行模型:fetch handler、ctx 與請求生命週期

Section titled “03. 執行模型:fetch handler、ctx 與請求生命週期”
  • 學習目標:掌握一次 invocation 的完整生命週期,知道什麼時候程式碼會被中止。
  • 涵蓋:ES module handler 簽章 { fetch(request, env, ctx) }ctx.waitUntil() 與背景工作;ctx.passThroughOnException()request.cf 的地理/TLS 資訊;subrequest 限制(Free 50 / Paid 1000);CPU time vs wall time;全域作用域可以放什麼(唯讀常數、client 建構)、不能放什麼(任何 I/O);import { env } from "cloudflare:workers" 的 top-level 存取及其限制。
  • 獨立範例:一支 Worker 展示 waitUntil 有無的行為差異,用 log 證明背景工作被砍掉。
  • LinkForgeapps/redirector 第一版 — 硬編碼 map、302 redirect、waitUntil 記錄一筆 log。
  • 限制:Free 10ms / Paid 30s CPU(可設定到 5 分鐘)、128MB 記憶體、script size 壓縮後 Free 3MB / Paid 10MB、startup CPU 1s、subrequest Free 50 / Paid 10,000、同時等待 response header 的連線上限 6。
  • 篇幅:~2,800 字。

04. Bindings:env 是整個平台的介面

Section titled “04. Bindings:env 是整個平台的介面”
  • 學習目標:理解 binding 作為 capability 的設計哲學,以及它為什麼比環境變數字串好。
  • 涵蓋:binding 是能力而非連線字串(無需 credential、無需網路設定);vars vs secretswrangler secret put)vs Secrets Store;多環境(Wrangler environments,不是已棄用的 Service Environments);型別如何從 wrangler.jsonc 流到 TS;process.env 在文字 binding 上的自動填充。
  • 獨立範例:同一支 Worker 在 dev/staging/prod 三組 binding 下的行為。
  • LinkForge:定義完整 Env 介面與環境切分策略。
  • 陷阱:把 secret 寫進 vars;用 --env 覆蓋時忘記 binding 不會繼承。
  • 篇幅:~2,200 字。

  • 學習目標:建立一套可長期維護的 API 分層,並解決 Hono Env 與 Wrangler Env 的型別衝突。
  • 涵蓋
    • hono@4.x沒有 v5);new Hono<{ Bindings: CloudflareBindings; Variables: {...} }>()
    • wrangler types --env-interface CloudflareBindings — 避開 Hono 自己的 Env 型別被 shadow。
    • Middleware:corslogger、自訂 auth、錯誤處理與 HTTPException
    • 驗證:@hono/zod-validator(或 @hono/standard-validator,Standard Schema v1,較有未來性)。
    • @hono/zod-openapi 產生 OpenAPI 文件(注意 v1 起只吃 Zod 4)。
    • Hono RPC:hc<AppType> 的硬性條件(兩端同版本、strict: true、路由必須鏈式定義、務必明寫 status)。
  • 獨立範例:一支 CRUD API,含 zod 驗證、錯誤處理、OpenAPI 與型別安全 client。
  • LinkForgeapps/api 的路由分層、middleware stack、統一錯誤格式。
  • 陷阱hono/cloudflare-workersserveStatic 已棄用(綁在 Workers Sites 上),改用 assets 設定。
  • 篇幅:~3,500 字。

06. Cache API 與 HTTP 快取:edge 最被低估的一層

Section titled “06. Cache API 與 HTTP 快取:edge 最被低估的一層”
  • 學習目標:在打任何資料庫之前先想快取,並理解 Cloudflare 三層快取的差異。
  • 涵蓋caches.default vs caches.open();cache key 設計(含 Vary 陷阱);Cache-Control / s-maxage / stale-while-revalidate;Cache Rules 與 Tiered Cache;cf.cacheEverything / cf.cacheTtlByStatusfetch() 的用法;快取失效策略(purge API vs 版本化 key);為什麼 Cache API 常比 KV 快也比 KV 便宜。
  • 獨立範例:同一個昂貴 upstream 查詢,比較「無快取 / Cache API / KV」的延遲與成本。
  • LinkForge:redirect 熱路徑加上 Cache API 前置層。
  • 陷阱:Cache API 是每個 colo 獨立、不保證留存;把它當持久儲存。
  • 篇幅:~2,800 字。

07. Static Assets 與全端 Worker(以及 Pages 的現況)

Section titled “07. Static Assets 與全端 Worker(以及 Pages 的現況)”
  • 學習目標:能正確設定靜態資源,並對 Pages vs Workers 給出有依據的建議。
  • 涵蓋
    • assets五個欄位directorybindinghtml_handlingnot_found_handlingrun_worker_first
    • not_found_handling 預設是 "none" — SPA 必須明確設成 "single-page-application",這是最常見的白畫面來源。
    • run_worker_first: ["/api/*", "!/api/docs/*"] 的路由陣列形式。
    • env.ASSETS.fetch() 只有這一個方法。
    • _headers(上限 100 條)/ _redirects(上限 2,100 條)在 Workers 上的支援,以及它們不作用於 Worker 產生的 response
    • Pages 的正確表述:官方說法是「新專案請用 Workers」、「所有投資都在 Workers」,但 Pages 並未宣告 deprecated、也沒有 maintenance mode banner。誠實說明剩餘差距:file-based routing(functions/)、Pages Plugins、branch alias、非 Cloudflare zone 的自訂網域。
  • 獨立範例:一個 Worker 同時服務 SPA 與 /api/*
  • LinkForge:把 dashboard build 產物掛上去。
  • 陷阱:宣稱 Pages 已死(會失去讀者信任);experimental_serve_directly(已移除)。
  • 篇幅:~2,600 字。


08. Workers KV:最終一致性要怎麼用才對

Section titled “08. Workers KV:最終一致性要怎麼用才對”
  • 學習目標:把 KV 用在它擅長的地方,並能說出三個絕對不該用 KV 的情境。
  • 涵蓋
    • get(key, "text"|"json"|"arrayBuffer"|"stream"),效能由快到慢:stream → arrayBuffer → text → json。
    • Bulk readget(keys[], type?) 回傳 Map最多 100 key、只支援 text/json、只計 1 次 operation
    • getWithMetadataputexpirationTtl最小 60 秒)與 metadata(≤1024 bytes)。
    • list() 必須看 list_complete 而非 keys.length
    • cacheTtl 最小值 2026-01-30 起由 60s 降為 30s,預設仍是 60s。
    • 一致性:全球傳播「最多 60 秒或更久」,read-your-own-write 不保證。負向查詢(404)也會被快取、也會計費。
    • 每個 key 每秒 1 次寫入上限 —— 這條規定直接判死計數器、sliding session、last-seen 等模式。
  • 獨立範例:feature flag 服務,示範傳播延遲的實測。
  • LinkForge:redirect 熱路徑改用 KV;設計 link:{slug} key 與 metadata(放 tenant id + 狀態,省一次 D1 查詢)。
  • 限制/計費:Free 10 萬讀/日、1000 寫/日、1GB;Paid 每百萬讀 $0.50、每百萬寫/刪/list $5.00。key 512B、value 25MiB、單次 invocation 上限 1000 次 KV 操作
  • 陷阱:把 KV 當強一致資料庫、當計數器、當 queue;用 binding 做 bulk write(不支援,只能走 REST/Wrangler)。
  • ⚠️ 時效:舊版 REST 路徑 /accounts/{id}/workers/namespaces/* 2026-10-15 停用,改用 /accounts/{id}/storage/kv/namespaces/*
  • 篇幅:~3,200 字。

  • 學習目標:建立 D1 資料庫、跑 migration、寫出符合 D1 計費模型的查詢。
  • 涵蓋:D1 = SQLite + 全球讀取複本;prepare().bind().run()/.first()/.all()/.raw()batch() 是隱式 transaction,單次網路往返;migrations_dirwrangler d1 migrations create/apply(含 --local / --remote);meta 欄位(rows_readrows_writtendurationserved_by)——rows_read 是計費單位,index 設計直接等於帳單;Time Travel(Free 7 天 / Paid 30 天)。
  • 獨立範例:一個 todo API,刻意示範缺 index 時 rows_read 如何爆炸。
  • LinkForgetenants / users / links / click_rollup schema 第一版與初始 migration。
  • 限制:Free 10 個 DB、單庫 500MB、500 萬讀列/日;Paid 5 萬個 DB、單庫 10GB、每次 invocation 1000 次查詢;查詢逾時 30s、單一 statement 100KB、綁定參數 100 個、單列 2MB。
  • 陷阱:用 exec() 跑應用查詢(官方明確不建議,效能與安全都差);傳 undefinedbind()D1_TYPE_ERROR);期待 BigInt;以為 boolean 有原生型別。
  • 篇幅:~3,200 字。

10. D1 + Drizzle ORM:型別安全的資料層

Section titled “10. D1 + Drizzle ORM:型別安全的資料層”
  • 學習目標:建立可維護的 schema-first 工作流,並避開目前版本線的地雷。
  • 涵蓋
    • 版本抉擇(本篇最重要的一段)drizzle-orm npm latest0.45.x,但 orm.drizzle.team 官網預設文件是 v1.0.0-rc。兩條線 API 不同,必須先選定。
    • v0 → v1 的破壞性變更:SQLite driver 的 schema 選項被 Omit 掉,改用 relationsrelations()defineRelations()casing 選項移除;drizzle-zod 等併入主套件;getTableColumns()getColumns()
    • migration 佈局不相容:drizzle-kit 0.31.x 輸出 0000_x.sql + meta/_journal.jsonwrangler d1 migrations apply 吃得到);drizzle-kit 1.0-rc 改成 out/<ts>_<name>/migration.sql 資料夾式,wrangler 找不到。本篇給出兩條線各自的可行工作流。
    • driver: 'd1-http' 支援 migrate / push / pull / studio
    • db.transaction() 在 D1 上型別過得了、執行必炸(D1 拒絕裸 BEGIN/SAVEPOINT)。一律用 batch()
  • 獨立範例:完整 schema → migration → seed → query 的一輪。
  • LinkForgepackages/db 落地,含 relational query 與 batch() 寫入。
  • 陷阱:以為 ORM 幫你擋掉 transaction 問題;migration 目錄結構與 wrangler 不對齊。
  • 篇幅:~3,600 字(本系列最容易踩雷的一篇)。

11. D1 進階:Read Replication 與 Sessions API

Section titled “11. D1 進階:Read Replication 與 Sessions API”
  • 學習目標:正確啟用全球讀取複本,理解 bookmark 的一致性語意。
  • 涵蓋
    • 讀取複本目前仍是 beta;在 dashboard 或 REST 開啟(read_replication.mode = "auto"),關閉需最多 24 小時。
    • 六個區域:ENAM / WNAM / WEUR / EEUR / APAC / OC。
    • 最關鍵的一句話:不呼叫 withSession(),所有查詢仍然打 primary,複本等於沒開。
    • 三種 constraint:first-unconstrained(預設,最低延遲)、first-primary(最新資料)、<bookmark>(sequential consistency)。
    • 慣用模式:讀取 x-d1-bookmark header → withSession(bookmark ?? "first-unconstrained")session.getBookmark() → 寫回 response header。
    • Sessions API 只能透過 Worker binding,REST API 不支援
    • Drizzle 相容性:v1 RC 的 AnyD1Database 已含 D1DatabaseSession;0.45.x 需要 cast(runtime 可用)。
  • 獨立範例:一個 read-after-write 場景,示範不用 bookmark 時使用者看到舊資料。
  • LinkForge:dashboard 讀取路徑套用 session + bookmark。
  • 篇幅:~2,800 字。

  • 學習目標:正確使用 R2 的 API 與成本模型。
  • 涵蓋get/put/head/delete/listput 是強一致;conditional request 的慣用寫法 —— 直接把 request headers 丟進去:onlyIf: request.headersrange: request.headers;multipart upload(單 part 5GiB、最多 10,000 parts、未完成 7 天自動 abort);writeHttpMetadata();storage class(Standard / Infrequent Access);event notifications → Queues(GA);presigned URL 與自訂網域。
  • 獨立範例:可續傳的大檔上傳 + Range request 串流下載。
  • LinkForge:CSV 匯出、QR code、OG image 存放。
  • 計費陷阱(本篇核心)egress 永遠免費,但 ListObjects 屬於 Class A($4.50/百萬)Get/Head 是 Class B($0.36/百萬),delete 免費。一個天真的「列出所有物件再逐一處理」迴圈就是帳單殺手。
  • 陷阱:production 使用 r2.dev 公開網址(官方明講「不供 production 使用」,速率不定);R2 Data Catalog / R2 SQL 目前仍是 beta,不要當 GA 教。
  • 篇幅:~3,000 字。

13. 儲存選型:KV / D1 / R2 / DO storage / Hyperdrive 決策樹

Section titled “13. 儲存選型:KV / D1 / R2 / DO storage / Hyperdrive 決策樹”
  • 學習目標:面對一個新需求,能在五分鐘內選對儲存並說出理由。
  • 涵蓋:一致性模型對照(eventual / strong / serializable);讀寫比例;單 key 熱點;資料大小;查詢複雜度;成本維度差異(KV 算 operation、D1 算 rows read、R2 算 class A/B、DO 算 GB-s + 儲存)。以 LinkForge 的六個實際需求逐一走過決策。
  • 產出:一張決策流程圖 + 一張成本維度對照表(本篇是全系列最常被回頭查的一篇)。
  • 篇幅:~2,400 字,圖表為主。


  • 學習目標:認出「只有 DO 能解」的問題形狀,並寫出第一個 DO。
  • 涵蓋
    • 每個 DO 全球唯一、單執行緒、有身分 —— 這三點合起來解決的是**協調(coordination)**問題,不是儲存問題。
    • 2026 年的正確寫法:import { DurableObject } from "cloudflare:workers"class X extends DurableObject,constructor 是 (ctx, env)(官方文件註明:舊稱 state,現在叫 ctx)。
    • Addressing:優先用 env.MY_DO.getByName("foo"),而非 idFromName() + get()
    • RPC method 優先於 fetch() —— 非 HTTP 語意的互動不該包成 Request。
    • Migration:new_sqlite_classes 是新專案的唯一選擇new_classes(KV-backed)是 legacy,且新帳號已無法建立。
    • blockConcurrencyWhile() 的正確用途(初始化)與誤用(當鎖用)。
    • Location hints(含 2026 新增的 apac-ne / apac-se)。
  • 獨立範例:一個全域唯一的 rate limiter。
  • LinkForgeLinkCounter DO —— 解決「KV 每秒 1 寫」擋掉的即時計數需求。
  • 陷阱:DO class 沒有 extends DurableObject;用 new_classes;把 DO 當一般資料庫(單物件約 1,000 req/s 軟上限)。
  • 篇幅:~3,400 字。

15. DO SQLite Storage:每個 object 一顆資料庫

Section titled “15. DO SQLite Storage:每個 object 一顆資料庫”
  • 學習目標:使用 SQLite-backed storage,理解它與 D1 的定位差異。
  • 涵蓋ctx.storage.sql.exec(query, ...bindings) 回傳 SqlStorageCursor.toArray().one().raw()columnNamesrowsReadrowsWritten);同步 KV API ctx.storage.kv.*(僅 SQLite-backed);transactionSync() —— DO 內部有真正的 transaction,這是它相對 D1 的關鍵優勢;ctx.storage.sync();PITR:getCurrentBookmark() / getBookmarkForTime() / onNextSessionRestoreBookmark(),30 天視窗;每個 object 上限 10GB
  • 獨立範例:一個協作文件的 per-document DO,含真 transaction 與 PITR 還原。
  • LinkForgeLinkCounter 用 SQLite 存明細,取代記憶體變數。
  • 限制/計費:Free 100k req/日 + 13,000 GB-s/日;Paid 每百萬 req $0.15、每百萬 GB-s $12.50、儲存每 GB-月 $0.20(含 5GB)。hibernate 中的閒置 object 不計 duration
  • 陷阱:把非同步 KV storage API 當主要儲存介面教(那是舊介面);忽略 rowsRead 就是帳單。
  • 篇幅:~3,000 字。

16. WebSocket Hibernation:讓一萬條連線幾乎不花錢

Section titled “16. WebSocket Hibernation:讓一萬條連線幾乎不花錢”
  • 學習目標:用 hibernation API 做即時功能,理解它與傳統 WebSocket 寫法的成本差異。
  • 涵蓋ctx.acceptWebSocket(ws, tags?) + webSocketMessage / webSocketClose / webSocketError handler;getWebSockets(tag?)getTags(ws)setWebSocketAutoResponse()(ping/pong 完全不喚醒 object);setHibernatableWebSocketEventTimeout();訊息上限 2025-10 起由 1MiB 提升到 32MiB
  • 成本對比(本篇核心)ws.accept() + addEventListener 會讓 object 持續存活、持續累積 GB-s;ctx.acceptWebSocket() 讓 object 在閒置時被驅逐、連線由 runtime 保持。同樣 1,000 條閒置連線,帳單差好幾個數量級。
  • 獨立範例:多人游標同步房間。
  • LinkForgeLiveDashboard DO —— 即時點擊看板。
  • 陷阱:混用兩種 API;在 hibernation 模式下依賴 instance 記憶體狀態(object 會被驅逐,狀態必須落在 storage)。
  • 篇幅:~3,200 字。

17. DO Alarms:內建的排程與去抖動

Section titled “17. DO Alarms:內建的排程與去抖動”
  • 學習目標:用 alarm 取代大部分「需要一個 cron」的直覺。
  • 涵蓋setAlarm() / getAlarm() / deleteAlarm()alarm(alarmInfo?) handler;at-least-once 語意 + 指數退避重試 —— handler 必須 idempotent;alarm 與 hibernation 的互動;2026-02 起 deleteAll() 也會刪 alarm
  • 模式:debounce(大量寫入合併成一次落庫)、per-entity 排程(每個使用者自己的到期時間,不需要掃全表的 cron)、TTL 清理。
  • 獨立範例:一個把高頻寫入 debounce 成每 10 秒落庫一次的 aggregator。
  • LinkForgeLinkCounter 用 alarm 每 30 秒把計數 flush 進 D1 rollup 表。
  • 篇幅:~2,600 字。

18. Workers RPC 與 Service Bindings:把單體拆開

Section titled “18. Workers RPC 與 Service Bindings:把單體拆開”
  • 學習目標:用 RPC 做服務拆分而不付出網路代價。
  • 涵蓋
    • services binding 的三個欄位:bindingserviceentrypoint;也支援 remote: true
    • class X extends WorkerEntrypointthis.env / this.ctx 是 class 屬性。
    • 最大誤解:每次 invocation 都是新 instance,不能跨 request 保留狀態。
    • 可跨邊界傳遞:structured-cloneable(上限 32MiB)、function(變成 callback stub)、RpcTarget 子類實例、stream、Request/Response、stub。不是 RpcTarget 子類的 class 傳不過去。
    • Promise pipelining:省掉中間的 await 可以把多趟往返壓成一趟。
    • 資源釋放:using counter = await env.SVC.newCounter()(Wrangler v4 原生支援);Symbol.asyncDispose 不支援
    • 保留字:fetchconnectdupconstructor
    • fetch 式 service binding 並未棄用,只是 RPC 是建議預設。
  • 獨立範例:把一個單體 Worker 拆成 api + auth 兩支,用 RPC 串起來並示範 pipelining 的延遲差異。
  • LinkForge:抽出 TenantService,讓 redirector 與 api 共用。
  • 篇幅:~3,000 字。

Part 4 — 非同步與事件流(5 篇)

Section titled “Part 4 — 非同步與事件流(5 篇)”

  • 學習目標:建立可靠的非同步管線,並算得出它的帳單。
  • 涵蓋:producer/consumer 設定(max_batch_sizemax_batch_timeoutmax_retriesdead_letter_queuemax_concurrencyretry_delay);send() / sendBatch()contentType 預設是 "json");delaySeconds(0–86400);consumer 的 queue(batch, env, ctx)message.ack() / retry({delaySeconds}) / batch.ackAll() / retryAll()attempts 從 1 開始metrics() 讀 backlog;pull consumer(HTTP,含 visibility_timeout_ms 與 lease)。
  • 計費模型(必講):一次 operation = 每 64KB 的寫、讀、或刪。一則典型訊息 = 3 次 operation,每次 retry 再加一次讀。Free 每日 10,000 operations;Paid 每百萬 $0.40。
  • 獨立範例:webhook fan-out,含毒訊息進 DLQ。
  • LinkForge:redirect 熱路徑只做 send()apps/consumers 負責寫 Analytics Engine + D1 rollup。
  • 限制:訊息 128KB、sendBatch 100 則 / 256KB、每佇列 5,000 msg/s、backlog 25GB、push consumer 250 併發、consumer wall clock 15 分鐘。Free 保留期固定 24 小時且不可調
  • 陷阱:宣稱 Queues 需要付費方案(已非事實);期待順序保證(只有 best-effort);移除 consumer worker 後忘了清掉 queues.consumers 區塊(deploy 會失敗)。
  • 篇幅:~3,400 字。

  • 學習目標:寫出可測試的排程任務,知道什麼時候不該用 cron。
  • 涵蓋triggers.crons(支援 LW 之類的擴充語法);scheduled(controller, env, ctx)controller.cron / .scheduledTime / .noRetry()本機測試的正確方式:純 wrangler dev + curl "http://localhost:8787/cdn-cgi/handler/scheduled?cron=*+*+*+*+*&time=..."
  • ⚠️ 不要教wrangler dev --test-scheduled/__scheduled —— 兩者都已從現行文件消失。
  • 限制:cron 是帳號層級配額,Free 5 / Paid 250;CPU Free 10ms、Paid 30s(<1 小時間隔)/ 15 分鐘(≥1 小時間隔);wall clock 一律 15 分鐘;變更最多 15 分鐘生效。
  • 何時不該用 cron:需要 per-entity 排程時用 DO alarm;需要長時間多步驟時用 Workflows。
  • LinkForge:每日清理過期連結。
  • 篇幅:~2,000 字。

  • 學習目標:把多步驟、跨小時甚至跨月的流程寫成看起來像同步程式碼的東西。
  • 涵蓋class X extends WorkflowEntrypoint<Env, Params>run(event, step)step.do(name, config?, cb) 的重試設定;step.sleep / sleepUntil不計入 step 上限);step.waitForEvent(name, {type, timeout})(預設 24 小時,逾時會 throw);instance API:create / createBatch / getstatus / pause / resume / terminate / restart / sendEvent2026-06 新增 schedules 設定(Workflow 自帶 cron);step 可回傳 ReadableStream<Uint8Array> 以突破 1MiB 結果上限。
  • 關鍵教學點waiting 狀態的 instance 不計入併發配額 —— 可以同時有數百萬個 instance 在睡覺。
  • Workflows vs Queues vs DO alarm 的分工表。
  • 限制:steps Free 1,024 / Paid 10,000(可申請 25,000);併發 Free 100 / Paid 50,000;step 結果 1MiB;保留 Free 3 天 / Paid 30 天。
  • 獨立範例:訂單處理流程,含人工審核(waitForEvent)與補償步驟。
  • LinkForge:每週報表 Workflow —— 聚合 → 產 CSV 進 R2 → 寄信。
  • 註記Dynamic Workflows(2026-05)是建在 Dynamic Workers 上的開源函式庫(@cloudflare/dynamic-workflows,open beta),不是 Workflows v2、也不是它的替代品,留到 Part 6 再談。
  • 篇幅:~3,400 字。

22. Analytics Engine:自己蓋分析後台

Section titled “22. Analytics Engine:自己蓋分析後台”
  • 學習目標:寫入高基數時序資料並寫出正確的聚合查詢。

  • 涵蓋writeDataPoint({ blobs, doubles, indexes }) —— 非阻塞、不需 awaitblobs 是字串維度(最多 20,總計 ≤16KB)、doubles 是數值(最多 20)、indexes 只能有一個(sampling key,≤96 bytes);SQL API(ClickHouse 方言)走 POST /accounts/{id}/analytics_engine/sql

  • Sampling(本篇的靈魂):寫入端與查詢端都會抽樣,_sample_interval 是每列各自的抽樣倒數。

    想算
    計數count()sum(_sample_interval)
    加總sum(bytes)sum(bytes * _sample_interval)
    平均avg(bytes)sum(bytes*_sample_interval)/sum(_sample_interval)
    分位數quantile(0.5)(bytes)quantileExactWeighted(0.5)(bytes,_sample_interval)
  • 限制:每次 invocation 250 個 data point、保留 3 個月;Free 每日 10 萬寫入 / 1 萬查詢。目前尚未開始計費(官方仍寫「未來數月才開始」)—— 要標註查證日期。

  • 獨立範例:API latency 儀表板 + Grafana 接入。

  • LinkForge:完整點擊分析後台(來源國家、referrer、UA、時間序列)。

  • 篇幅:~3,000 字。


23. Pipelines 與 R2 SQL:把事件落地成資料湖(beta)

Section titled “23. Pipelines 與 R2 SQL:把事件落地成資料湖(beta)”
  • 學習目標:了解 Cloudflare Data Platform 的三件式模型,判斷現在該不該用。
  • 涵蓋Streams / Pipelines / Sinks 三物件模型(2025-09 重構,建在 Arroyo 之上);HTTP ingest 或 Worker binding;SQL transform(stateless only,且建立後不可修改,只能刪除重建);sink 到 R2(JSON/Parquet)或 R2 Data Catalog(Apache Iceberg),exactly-once;用 wrangler r2 sql query 讀回來。
  • ⚠️ binding 鍵名已更名:現在是 { "binding": "X", "stream": "<STREAM_ID>" };舊的 "pipeline" 仍可用但會警告,且官方部分文件頁仍是舊的
  • 狀態:open beta、僅 Workers Paid。計費訊號目前官方頁面互相矛盾(changelog 說尚未開始計費,pricing 頁列出費率),文章中要明講並要求讀者自行確認。
  • 獨立範例:從 HTTP ingest 到 Iceberg 表的完整一輪。
  • LinkForge:點擊事件的長期歸檔(標為 optional,因為需要付費方案)。
  • 篇幅:~2,600 字,明確標示 beta。


⚠️ 本篇是全系列時效性最強的一篇。 React Router v8.0(2026-06 GA)移除了 AppLoadContext,2025 年幾乎所有教學(包含 Cloudflare 官方 RR 指南與官方 starter template)的 binding 存取寫法在 v8 上會直接 throw。

  • 學習目標:用 v8 的正確方式部署 SSR 全端應用。
  • 涵蓋
    • 新的 binding 存取方式(C3 實際產出的寫法):loader 直接 import { env } from "cloudflare:workers"完全不用 load context
    • 需要顯式 context 時:createContext() + RouterContextProvidercreateRequestHandler 現在會硬性拒絕普通物件)。
    • vite.config.tscloudflare({ viteEnvironment: { name: "ssr" } }) + reactRouter()
    • 通常不用寫 assets 區塊 —— vite build 會自動產出含 assets.directorywrangler.json
    • v8 baseline:Node ≥22.22、React ≥19.2、Vite 7/8(Vite 6 不再相容);middleware 已是預設功能。
    • 已移除:cloudflareDevProxy()@react-router/dev/vite/cloudflarereact-router-dom
    • SPA mode 與 prerendering 不支援 Cloudflare Vite plugin(官方明載)。
  • 獨立範例:一個含 loader / action / middleware 的 SSR app,直接讀 D1。
  • LinkForgeapps/dashboard 落地,搭配 TanStack Query 做 client 端快取。
  • 篇幅:~3,600 字。

⚠️ 同樣有大版本斷層:Astro 7 + @astrojs/cloudflare v14Astro.locals.runtime.* 在 adapter v13 已移除、v14 連警告都拿掉,現在直接失敗。

  • 學習目標:用 adapter v14 部署內容站與混合 SSR。
  • 涵蓋
    • 設定已成 zero-config:adapter: cloudflare()
    • 新的存取方式import { env } from 'cloudflare:workers'Astro.request.cfcaches.defaultAstro.locals.cfContext.waitUntil()
    • 已移除:platformProxyroutes / _routes.jsoncloudflareModulesworkerEntryPoint、泛型 Runtime<Env> 型別。
    • Sessions 自動設定:adapter 自動注入 KV driver,wrangler 部署時自動 provision namespace,Astro.session?.get() 直接可用。
    • Images:Sharp 是原生 libvips addon,在 workerd 跑不起來(v13 起連 astro dev 都是 workerd),預設已改為 imageService: 'cloudflare-binding'
    • Adapter v13 起完全不再支援 Pages
    • 多環境部署改為 CLOUDFLARE_ENV=staging astro build && wrangler deploy(plugin 在 build 時解析環境)。
  • ⚠️ 不要用 npm create cloudflare -- --framework=astro —— C3 目前產出的 template 仍然塞入已不存在的 platformProxy 與失效的 Runtime<Env>。改用 npm create astro@latest + npx astro add cloudflare
  • 獨立範例:Content Collections 內容站 + 一條 SSR API route。
  • LinkForgeapps/site 行銷頁與文件。
  • 篇幅:~3,000 字。

26. 前後端整合:型別共享與 monorepo

Section titled “26. 前後端整合:型別共享與 monorepo”
  • 學習目標:讓一份型別從 D1 schema 一路流到 React component。
  • 涵蓋:Drizzle schema → zod → Hono route → hc<AppType> → TanStack Query;pnpm workspace 與 @repo/* 內部套件;@cloudflare/vite-pluginauxiliaryWorkers一個指令同時跑多個 Worker,service binding 與 RPC 在本機就能通);devOnly worker;輸出目錄是 dist/<vite-environment-name>(不是 worker 名稱)。
  • 獨立範例:兩個 Worker + 一個前端,本機一鍵啟動。
  • LinkForge:完整 monorepo dev 體驗定案。
  • 篇幅:~2,800 字。

  • 學習目標:在沒有長駐 process、CPU 受限的環境下做對認證。
  • 涵蓋
    • Session 儲存選型:KV(Cloudflare 官方建議,但 read-your-own-write 不保證 → 登出/撤銷有漏洞窗口;每 key 每秒 1 寫 → sliding expiration 做不了)vs DO(立即撤銷、單次性 token、rate limit)vs D1(要 join user 資料時)。
    • 密碼雜湊的 CPU 陷阱(本篇最實用的一段)
      • node:crypto scrypt(需 nodejs_compat)—— 目前最佳解,N*r*p ≤ 1,048,576
      • PBKDF2 在 production 被硬限制在 100,000 次迭代(OWASP 建議 600,000);更糟的是 workerd 本機版沒有這個限制 —— 600k 在 wrangler dev 會過、部署後炸 NotSupportedError
      • bcrypt/argon2 原生模組、WebAssembly.compile() 皆不可用。
      • Free plan 10ms CPU 根本跑不完 scrypt,密碼登入實質上需要 Paid。
    • 函式庫現況:Better Auth 可用但 Cloudflare 官方零支援(無 guide、無 template、@better-auth/cloudflare 不存在;社群套件是 better-auth-cloudflare),且必須 per-request 建構 auth 實例;Auth.js@auth/core + @auth/d1-adapter)是最乾淨的路徑、core 甚至不需要 nodejs_compatLucia 已棄用OpenAuth 已停更約 16 個月(不要開新專案用)。
    • session.cookieCache 是 Workers 上投報率最高的一個開關 —— 省掉每個已登入請求的一次 D1/KV 往返。
    • JWT:jose@6(零依賴、純 WebCrypto、不需任何 flag)、hono/jwtverifyWithJwks();Cloudflare Access 要驗 Cf-Access-Jwt-Assertion header(不是 cookie),且一定要驗 aud,否則同 team 任一 app 的 token 都會被接受。
    • Workers 專屬 crypto:crypto.subtle.timingSafeEqual()new crypto.DigestStream()、原生 Ed25519。
  • 獨立範例:email + password 登入(DO session store)與 OAuth 登入(Auth.js)兩版對照。
  • LinkForge:多租戶 auth、role、API token。
  • 篇幅:~4,000 字(全系列最長)。


28. Hyperdrive:接上你既有的 Postgres / MySQL

Section titled “28. Hyperdrive:接上你既有的 Postgres / MySQL”
  • 學習目標:讓 Workers 能用既有關聯式資料庫,並避開快取一致性陷阱。
  • 涵蓋hyperdrive binding + 必要的 nodejs_compat;Postgres 用 pg≥8.13 或 postgres.jsnew Client({ connectionString: env.HYPERDRIVE.connectionString })MySQL 必須用離散欄位而非 connectionString,且 mysql2 必須加 disableEval: true(Workers 沒有 eval())—— 這是 MySQL 使用者第一大坑;localConnectionString 讓本機 dev 也能連。
  • ⚠️ 最重要的正確性陷阱query cache 不會因為寫入而失效max_age 預設 60s,stale_while_revalidate 15s)。read-after-write 路徑必須用第二組 --caching-disabled 設定。
  • 限制:Free 10 / Paid 25 個設定;連線數 Free ~20 / Paid ~100;查詢最長 60s;快取回應上限 50MB。
  • 獨立範例:既有 Postgres 上的 API,示範快取命中率與寫後讀錯誤。
  • LinkForge:模擬「從既有系統遷移」的章節(optional path)。
  • 篇幅:~2,800 字。

  • 學習目標:知道什麼工作該掉出 isolate,並正確設定容器生命週期。
  • 涵蓋
    • 容器一定由一個 Durable Object 當前門 —— containers[].class_name 必須與 durable_objects.bindings[].class_name 一致,而 env 上出現的是 DO binding 的 name。這是最多人設定錯的地方。
    • migration 必須用 new_sqlite_classes
    • Container class(@cloudflare/containers):defaultPortsleepAfter(預設 "10m")、envVarsenableInternet;hooks onStart / onStop / onError / onActivityExpired()(必須呼叫 stop()destroy(),否則容器洩漏)
    • Instance types:lite / basic / standard-1standard-4舊的 dev 與裸 standard 已不存在);上限 4 vCPU / 12GiB。
    • 計費:每 10ms 實際執行時間,GA 起改為 active-CPU 計價,閒置 wall-clock 不計。
    • 沒有 GPU container(唯一相關資料是 2024 年談 Cloudflare 內部平台的文章,不適用)。
    • Sandboxes@cloudflare/sandbox)是建在 Containers 上的另一個產品,專供不可信程式碼執行,不要混談。
  • 獨立範例:用容器跑 ffmpeg 轉檔,由 Worker 排程。
  • LinkForge:optional —— 大量 QR/PDF 批次產生。
  • 篇幅:~3,000 字(Workers Paid only,明確標註)。

30. Browser Run(原 Browser Rendering)

Section titled “30. Browser Run(原 Browser Rendering)”

⚠️ 2026-04-15 更名為 Browser Run,文件路徑改為 /browser-run/。但三件事沒變:REST 路徑仍是 .../browser-rendering/...、wrangler 鍵名仍是 browser、套件仍是 @cloudflare/puppeteer / @cloudflare/playwright

  • 學習目標:產生截圖 / PDF,並且不要燒錢。
  • 涵蓋:Quick Actions(/content/screenshot/pdf/snapshot/markdown/scrape/json/links,均 GA;/accessibilityTree 2026-07 新增;/crawl 仍 beta);2026-05 新增的 binding 版 env.BROWSER.quickAction("screenshot", { url })(不需 API token,但必須 remote: true,本機不支援);Playwright 需 compatibility date ≥ 2025-09-15;session 重用(puppeteer.sessions() / connect())。
  • 成本控制(本篇核心):閒置 timeout 60 秒(可延長到 10 分鐘);重用模式結尾要用 browser.disconnect() 而非 browser.close();官方明指未關閉的 session 是失控帳單第一名。Free 3 併發 / 每日 10 分鐘;Paid 120 併發、含 10 browser-hours/月,之後 $0.09/hr。
  • Puppeteer vs Playwright:官方 FAQ 刻意不選邊。可以給出編輯觀點(Playwright 上游版本新得多),但不要宣稱這是 Cloudflare 的建議
  • LinkForge:每個連結自動產生 OG 預覽圖,存進 R2。
  • 篇幅:~2,600 字。

  • 學習目標:處理使用者上傳的圖片,理解 2026 年的計費模型變動。
  • 涵蓋images binding 的兩個介面 —— (a) 轉換:env.IMAGES.input(stream).transform({width}).output({format}),加上 .draw().info();(b) 2026-06 新增的 hosted 管理介面env.IMAGES.hosted.upload()/.list()/.image(id).*(Worker 裡不再需要 API token,但需付費 Images 方案)。fetch()cf.image 並未棄用,與 binding 分工不同(URL 來源 vs 位元組管線)。
  • ⚠️ 文件 IA 已重組/images/transform-images/*/images/optimization/*;「Image Resizing」一詞已退役,現在叫 transformations。
  • 計費變動2026-07-01 起,Images binding 改為按 unique transformation 計費(與 URL transform 同模型),而非按呼叫次數;.info() 不再計費。
  • 陷阱:把 resize Worker 掛在 /* 而不區分原圖/縮圖路徑 → 無窮迴圈;把 resize 選項放進 cacheKey;把 Polish 與 Transformations 混為一談。
  • LinkForge:使用者頭像與自訂 OG 圖處理。
  • 篇幅:~2,400 字。

Cloudflare 已把兩者收攏到新的 Cloudflare Email Service 傘下(/email-service/),文件正在從 /email-routing/ 搬遷。

  • 學習目標:讓 Worker 能收信也能寄信。
  • 涵蓋
    • Email Routing(GA,Free 可用) vs Email Sending(2026-04 起 public beta,僅 Workers Paid)
    • 舊規則已被推翻:以前只能寄給已驗證的目的地;現在網域 onboard 完成後即可寄給任意收件人,SPF/DKIM/DMARC 自動設定。
    • 現代寄信 API:{ "send_email": [{ "name": "EMAIL" }] } + await env.EMAIL.send({ to, from, subject, text, html, replyTo })。可選限制 allowed_destination_addresses / allowed_sender_addresses
    • legacyimport { EmailMessage } from "cloudflare:email" + mimetext 現已被官方標為「legacy API」。
    • 收信:async email(message, env, ctx)setReject() / forward() / reply()(reply 不需要 send_email binding,但需要有效 DMARC)。
    • 本機測試:/cdn-cgi/handler/email
  • LinkForge:週報寄送、team 邀請信、以及一個 support@ 收信 → 自動建 ticket 的流程。
  • 篇幅:~2,400 字。

33. 多租戶執行使用者程式碼:Workers for Platforms vs Dynamic Workers

Section titled “33. 多租戶執行使用者程式碼:Workers for Platforms vs Dynamic Workers”

2026 年最容易搞混的一對產品。本篇的主要價值就是把它們分乾淨。

  • 學習目標:面對「讓客戶跑他們自己的程式碼」需求時選對產品。
  • 涵蓋
    • Workers for Platforms(GA,$25/月方案)dispatch_namespaces binding;env.DISPATCHER.get(name, {}, { limits: { cpuMs, subRequests }, outbound })。注意 subRequests 的大寫 R(與多數 Cloudflare 設定慣例不同)。錯誤處理 e.message.startsWith("Worker not found") → 404。最佳實務是所有客戶共用一個 namespace,不是每個客戶一個。
    • Dynamic Workers(open beta,Workers Paid):產品化的 Worker Loader。[[worker_loaders]] binding;env.LOADER.get(id, async () => ({ compatibilityDate, mainModule, modules, globalOutbound })) —— get() 同步回傳 stub,callback 只在 cold isolate 執行且可能執行多次。globalOutbound: null 完全封死對外網路。能力導向:Dynamic Worker 只看得到你放進 env 的東西;自訂 API 走 ctx.exports loopback。計費:每月含 1,000 個 unique Worker,超出每個每日 $0.002。
    • 選擇準則:客戶自己 deploy Worker、你用名字 dispatch → Workers for Platforms;你的 Worker 在 runtime 載入生成的程式碼Dynamic Workers兩者互不取代。
    • DO Facetsthis.ctx.facets.get(name, cb) —— 屬於 Dynamic Workers,不是 Durable Objects 的核心功能。每個 facet 有自己隔離的 SQLite,適合 per-tenant / AI 生成的應用。
    • Dynamic Workflows@cloudflare/dynamic-workflows,MIT,open beta):解決「stock Workflows 要求 workflow class 存在於你部署的程式碼中」的問題,讓引擎幾小時後醒來時能重新進入正確租戶的程式碼。wrapWorkflowBinding() + createDynamicWorkflowEntrypoint(),且 DynamicWorkflowBinding 必須從 Worker Loader 再匯出(很容易漏)。
  • 獨立範例:一個讓使用者提交 JS 片段當作 webhook transformer 的平台。
  • LinkForge:optional —— 讓租戶自訂 redirect 前置邏輯。
  • 陷阱:把 Dynamic Workers 說成 GA;把 Dynamic Workflows 說成「Workflows v2」;說 Workers for Platforms 被取代了。
  • 篇幅:~3,200 字。


  • 學習目標:在 Worker 裡跑推論,並選對模型。
  • 涵蓋{ "ai": { "binding": "AI" } }(binding 形狀是 2025 年唯一能原封不動沿用的東西);env.AI.run(model, inputs, options) —— stream: true 放在第二個參數(inputs),不是第三個AiOptionsgatewaywebsocketreturnRawResponseextraHeaderssignalenv.AI.toMarkdown();function calling;JSON mode;prompt caching(extraHeaders: {"x-session-affinity": "ses_..."});2026-03 重新設計的 pull-based batch({queueRequest: true} → 以 request_id 輪詢)。
  • ⚠️ 2026 最大變化env.AI.run() 不再只跑 Workers AI。2026-04 起可呼叫第三方模型(await env.AI.run("openai/gpt-4.1-mini", {...}, { gateway: { id: "default" } })第三方必須帶 gateway)。要把三個概念分清楚:@cf/... Workers AI(Neurons 計費)/@cf/deepgram/... 夥伴模型(也是 Neurons)/openai/... 第三方(AI Gateway Unified Billing,credits + 5% 手續費,不需自備 API key)。
  • 🔴 模型清單陷阱(務必寫進文章)2026-05-30 一次下架 18 個模型,包括 @cf/meta/llama-3.1-8b-instructllama-3-8b-instruct、全部 llama-2-7b-chat-*@cf/mistral/mistral-7b-instruct-v0.1@cf/google/gemma-3-12b-it@cf/microsoft/phi-2Cloudflare 自家 quickstart、AI SDK 頁面、JSON mode 支援清單目前都還印著已死的 model ID。不要照抄官方範例。
  • 目前的旗艦 model ID@cf/moonshotai/kimi-k2.7-code@cf/zai-org/glm-4.7-flash@cf/openai/gpt-oss-120b(注意它吃 instructions + input,不是 messages)、@cf/meta/llama-4-scout-17b-16e-instruct;embedding @cf/google/embeddinggemma-300m
  • 計費:Neurons,每日 10,000 免費,超出 Paid 每千 $0.011。錯誤 3036 = 免費額度用盡;3040 = 容量不足,這個要教重試
  • LinkForge:連結目標的惡意內容掃描 + 自動摘要。
  • 篇幅:~3,000 字。

  • 學習目標:把 LLM 呼叫的快取、限流、觀測、成本統一管起來。
  • 涵蓋
    • 入口已經換位置:現在建議走 api.cloudflare.com/client/v4/accounts/{id}/ai/v1/chat/completions(以及 /responses/messages)。
    • 兩段式棄用鏈(兩端都已查證):Universal Endpoint 頁面標題直接寫「(Deprecated)」,指向 OpenAI-compatible endpoint;而那一頁自己又寫「本 endpoint 已棄用,請用 REST API」。Provider-specific endpoints 並未棄用
    • 2026-03 起,第一次帶認證的請求會自動建立名為 default 的 gateway,不必先手動建。
    • 沒有獨立的 AI Gateway binding —— 用同一個 ai binding:env.AI.gateway("name").patchLog() / .getLog() / .getUrl()。(gateway.run() 已從文件消失。)
    • GA 功能:analytics、logging、caching、rate limiting、retries/timeouts、23 家 provider、custom cost、OTel export、Logpush。Beta:spend limit、Dynamic Routing、DLP、Guardrails、BYOK、custom provider、WebSockets。
    • Header:cf-aig-cache-key / -cache-ttl / -skip-cache / -metadata(上限 5)/ -max-attempts(上限 5)/ -backoff / -request-timeout已棄用cf-cache-ttlcf-skip-cache
    • 認證陷阱:在 gateway.ai.cloudflare.com 上,Cloudflare token 放 cf-aig-authorizationAuthorization 留給 provider);在 api.cloudflare.com 上則是標準 Authorization: Bearer
    • Guardrails 用 @cf/meta/llama-guard-3-8b,增加約 500ms,且不支援 streaming。
    • AI Gateway 裡沒有 MCP 功能 —— MCP Server Portals 是 Cloudflare One / Zero Trust 的功能,名稱撞車害很多人繞路。
  • LinkForge:所有 AI 呼叫統一走 gateway,接上成本儀表板。
  • 篇幅:~2,600 字。

  • 學習目標:建立可用的語意搜尋,並理解它的一致性語意。
  • 涵蓋insert / upsert / query / queryById / getByIds / deleteByIds / describereturnMetadata 是字串列舉 'none' | 'indexed' | 'all',不是 booleantopK 上限 100,但 returnValues: truereturnMetadata: 'all' 時降為 50;filter 運算子 $eq/$ne/$in/$nin/$lt/$lte/$gt/$gte,filter JSON < 2048 bytes。
  • 🔴 兩個最常見的錯:(1) V2 的寫入是非同步的,回傳 mutationId,要幾秒後才可查詢 —— 教學一定要示範這個 eventual consistency,否則讀者的第一個 demo 就會「查不到」;(2) metadata filter 欄位必須在插入向量之前wrangler vectorize create-metadata-index 宣告。
  • 限制:每 index 1,000 萬向量、最多 1536 維、metadata 10KiB/向量、每 index 10 個 metadata index。空 index 免費。
  • 獨立範例:文件 RAG,含 chunking 策略與 embedding 模型選擇。
  • LinkForge:跨租戶的連結語意搜尋(用 namespace 做租戶隔離)。
  • 陷阱:V1 index(早已停止建立);returnMetadata: true
  • 篇幅:~3,000 字。

⚠️ 不要稱 Agents SDK 為 GA —— 文件裡沒有任何 GA/beta 宣告,版本仍是 0.x,minor 版就會破壞相容。

  • 學習目標:在 Workers 上建 stateful agent 與 MCP server。
  • 涵蓋
    • class Agent<Env, State, Props> extends Server<Env, Props>,繼承鏈是 DurableObject > Server > Agent —— agent 本質上就是一個 DO,Part 3 的知識直接複用。
    • State:initialStatethis.setState()this.sql\…“(同步)。
    • 頭號改名陷阱:server 端 hook 叫 onStateChanged(0.4.0 從 onStateUpdate 改名,兩個都覆寫會 throw),但 client 端 useAgent 的選項仍叫 onStateUpdate。兩個名字都活著,在不同地方。
    • Chat 已搬套件import { AIChatAgent } from "@cloudflare/ai-chat"useAgentChat from @cloudflare/ai-chat/reactagents/ai-chat-agentagents/ai-react 現在 import 就 throw。
    • 設定必需項:nodejs_compat、DO binding、new_sqlite_classes migration、以及有靜態資源時的 run_worker_first: ["/agents/*"](否則 SPA 會吞掉 agent 路由)。
    • 2026 新增:Fibers(durable execution,runFiber / ctx.stash())、sub-agents(用 DO facets,只有 parent 需要 binding)、agents-as-tools 與 human-in-the-loop(waitForApproval() 由 Workflows 支撐,可以等好幾個月)、Agent Skills。
    • MCP 三選一決策表createMcpHandler()(無狀態,不需 DO,新的預設)/McpAgent(需要 per-session 狀態時)/raw transport(完全控制)。
    • 🔴 McpServer 必須 per-request 建構 —— 2025 年流行的 module-scope singleton 在 MCP SDK 1.26+ 已是安全問題。
    • OAuth:@cloudflare/workers-oauth-provider v0.8.2務必升過 0.8.0(修了 cross-client token revocation 與 auth code exchange 缺陷),並設 allowPlainPKCE: false(預設是 true)。
    • Code Mode@cloudflare/codemode,beta):把 MCP tools 轉成 TypeScript API 讓 LLM 寫程式呼叫,需要 worker_loaders binding。
  • ⚠️ 不要教workers-mcp(2025-03 後已死)、mcp-handler(那是 Vercel 的無關套件,撞名)、宣稱支援 sampling / tool annotations / outputSchema(文件皆無)。MCP dev server 預設埠是 8788 不是 8787。
  • LinkForge:一個讓 AI 助理管理連結的 MCP server(OAuth 保護)。
  • 篇幅:~3,600 字。


⚠️ @cloudflare/vitest-pool-workers v0.13.0(2026-03)是破壞性重寫。網路上所有 2025 年的設定範例都不能用。

  • 學習目標:建立在真 workerd 裡跑的測試套件。
  • 涵蓋
    • 新設定形式是 plugin 不是 pool
      import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
      export default defineConfig({
      plugins: [cloudflareTest({ wrangler: { configPath: "./wrangler.jsonc" } })],
      });
    • 需要 vitest@^4.1.0;Vitest 2.x / 3.x 完全不支援。
    • 遷移對照:defineWorkersConfigcloudflareTest()poolOptions.workers.* → 直接傳選項;isolatedStorage / singleWorker → 移除(隔離改為 per-test-file);import { env, SELF } from "cloudflare:test"import { env, exports } from "cloudflare:workers"SELF.fetch()exports.default.fetch()fetchMock 完全移除(改用 MSW 或直接 mock globalThis.fetch)。套件內附 codemod。
    • ⚠️ exports 不像舊的 SELF 那樣暴露 Assets —— 測靜態資源要用 startDevWorker()
    • cloudflare:test 仍提供:createExecutionContextwaitOnExecutionContextcreateScheduledControllercreateMessageBatchrunInDurableObjectrunDurableObjectAlarmapplyD1Migrations,以及新的 evictDurableObject / abortAllDurableObjects
    • Workflow 測試 API(v0.9.0 起):introspectWorkflowInstance()disableSleeps()mockStepResult()mockEvent()waitForStatus() —— 不用真的等三天。
    • D1 migration 在測試中:readD1Migrations()(Node 端)+ applyD1Migrations()(setup file)。注意 drizzle-kit v1 的資料夾式 migration 佈局在這裡同樣會出問題。
    • ⚠️ 整合會自動注入 nodejs_compatno_nodejs_compat_v2export_commonjs_default —— 測試行為可能與 production 分歧,要在 wrangler config 明寫。
  • LinkForge:unit(DO 邏輯)+ integration(HTTP)+ Workflow 三層測試。
  • 篇幅:~3,400 字。

39. Observability:logs、traces 與 tail

Section titled “39. Observability:logs、traces 與 tail”
  • 學習目標:出事的時候找得到原因。
  • 涵蓋
    • observability 完整 schema(官方設定頁只寫了前兩個 key,是過時的):
      "observability": {
      "enabled": true, "head_sampling_rate": 1,
      "logs": { "enabled": true, "invocation_logs": true, "persist": true, "destinations": [] },
      "traces": { "enabled": true, "head_sampling_rate": 0.05, "persist": true, "destinations": [] }
      }
      注意 head_sampling_rate頂層(2025-04 的官方 blog 把它放在 logs 底下,是錯的)。
    • Workers Logs(GA):新 Worker 預設開啟。log JSON 物件才會被抽出欄位並建索引,Query Builder 才查得到巢狀欄位。保留 Free 3 天 / Paid 7 天(7 天是硬上限)。
    • Traces / OpenTelemetry(open beta,2026-03 起計費):零程式碼自動 instrument —— 所有 outbound fetch、所有 binding 呼叫(KV/R2/D1/DO/Queues/Browser/Images/Email)、cache、handler 生命週期。2026-05 起 service binding 與 DO 呼叫已支援分散式追蹤。自訂 span:import { tracing } from "cloudflare:workers"tracing.enterSpan(name, cb)
    • ⚠️ Trace 注意事項:span 名稱與 attribute 名稱官方明說尚未定案;非 I/O 操作可能顯示 0ms(Spectre 緩解);用 $metadata.service 而非 service.name 篩選 Worker。價格在兩個官方頁面互相矛盾($0.60/M vs $0.05/M),文章不要寫死數字。
    • Query Builder(GA)只查 logs dataset,不查 traces。
    • Tail Workerstail_consumers + async tail(events, env, ctx)events陣列);按 CPU time 計費而非請求數。
    • wrangler tail 定位:只適合 live debugging —— 最多 10 個併發觀察者、會抽樣、不留存。
    • Source maps:"upload_source_maps": true,上限 15MB(gzip),非同步抓取,不影響 CPU/效能
    • Logpush:dataset workers_trace_eventslogs + exceptions 共用 16,384 字元額度。
  • LinkForge:結構化 log 規範、trace 抽樣策略、錯誤告警。
  • 篇幅:~3,200 字。

  • 學習目標:建立可回滾的部署流程。
  • 涵蓋:Workers Builds(Git 整合)vs GitHub Actions(cloudflare/wrangler-action);versions 與 gradual deployment —— wrangler versions upload / deploy --version-id X@10%,以及漸進式發佈期間的 DO/Queue 相容性注意事項;rollback;preview URL 與 preview alias;secrets 在 CI 的處理(wrangler secret bulk、Secrets Store);wrangler types --check 在 CI 驗證型別是否過期;monorepo 的選擇性部署。
  • LinkForge:完整 GitHub Actions pipeline(typecheck → test → deploy staging → smoke test → 漸進式 production)。
  • 篇幅:~2,800 字。

  • 學習目標:在多租戶 SaaS 情境下把邊界劃清楚。
  • 涵蓋:secrets vs Secrets Store;每個租戶一個 DO 作為隔離邊界;D1 的 row-level 隔離要靠應用層(沒有 RLS);Vectorize namespace 做向量隔離;rate limiting(Rate Limiting binding vs DO vs WAF,三者取捨);Turnstile;CORS 與 CSRF;signed URL(R2、Images、Stream);使用者提供程式碼時的 globalOutbound: null;Zero Trust / Cloudflare Access 保護管理後台;依賴稽核(Workers 沒有 filesystem 但供應鏈風險一樣在)。
  • LinkForge:租戶隔離的威脅模型與逐項對策。
  • 篇幅:~3,000 字。

  • 學習目標:對任一設計估出月成本,並認出常見的燒錢模式。
  • 涵蓋:把全系列的計費維度收攏成一張表 —— Workers(請求 + CPU ms)、KV(operation,注意 404 也計費)、D1(rows read,index 即帳單)、R2(Class A 的 List 是陷阱,egress 免費)、DO(GB-s + 儲存,hibernation 省錢)、Queues(每 64KB 一次 operation,一則訊息約 3 次)、Workers AI(Neurons)、Browser Run(browser-hours + 併發)、Containers(active CPU)。
  • 五個經典燒錢模式:熱路徑上的 list()、缺 index 的 D1 查詢、非 hibernation 的 WebSocket、忘記 disconnect 的 browser session、無上限的 retry 迴圈。
  • 產出:一份 LinkForge 在 1 萬 / 100 萬 / 1 億次點擊/月三個量級的成本試算表,以及「什麼時候該離開 edge」的判準。
  • 篇幅:~2,800 字。


43. LinkForge 總回顧與 production checklist

Section titled “43. LinkForge 總回顧與 production checklist”
  • 完整架構圖與每個決策的回顧(為什麼這裡用 DO 而不是 D1、為什麼那裡用 KV 而不是 Cache API)。
  • Production checklist:observability、告警、備份(D1 Time Travel / DO PITR / R2 版本)、rate limit、成本告警、依賴更新策略、compatibility date 的升級節奏。
  • 沒有涵蓋的東西與延伸方向:Zaraz、Stream、Snippets、Zero Trust、Terraform provider。
  • 篇幅:~2,400 字。

項目數字
總篇數43
總字數估計125,000
獨立範例數40+(examples/chNN/
貫穿專案1(LinkForge,8 個 app/package)
建議節奏每週 2 篇,約 5 個月

建議發佈順序:Part 0–4(前 23 篇)是核心骨幹,必須按序。Part 5–7 可依讀者回饋調整順序。Part 8 雖然排在最後,但建議提前把第 38 篇(測試)與第 39 篇(observability)的精簡版插進 Part 2 之後,避免讀者累積 20 篇沒有測試的程式碼。


五、維護計畫(本系列的最大風險)

Section titled “五、維護計畫(本系列的最大風險)”

這份研究過程中最強烈的發現:Cloudflare 自家文件目前在多處自相矛盾或過時 —— AI Gateway 的兩段式棄用鏈、印著已下架 model ID 的 quickstart、缺少 traces 的 observability 設定頁、仍用 context.cloudflare.env 的 React Router 指南、產出無效設定的 C3 Astro template。

因此:

  1. 每篇文章頂端標示「最後驗證日期 + wrangler 版本 + compatibility date」。
  2. 所有程式碼範例以「能否實際部署成功」為準,不以官方文件頁面為準。 本系列的 examples repo 應該有 CI 每週跑一次真實部署。
  3. 維護一份 VERSIONS.md,鎖定:wrangler 4.114.x、@cloudflare/vite-plugin 1.47.x、@cloudflare/vitest-pool-workers 0.18.x、hono 4.12.x、react-router 8.3.x、astro 7.1.x + @astrojs/cloudflare 14.1.x、drizzle-orm明確選定 0.45.x 或 1.0-rc)。
  4. 維護一份「不要教」清單(見附錄),每季複查一次。

Service Worker 語法(addEventListener('fetch'))· wrangler publish · Workers Sites [site] · node_compat · usage_model · getBindingsProxy() · 手動加 nodejs_compat_v2 · 假設 wrangler kv/d1/r2 指令會打 production(v4 起預設本機)· experimental_remote(已改名 remote

KV 當強一致資料庫 / 計數器 / queue · KV binding 做 bulk write · D1 exec() 跑應用查詢 · D1 dump() · 以為不用 withSession() 也會走 replica · 說 D1 read replication 是 GA · R2 r2.dev 用於 production · 說 R2 Data Catalog / R2 SQL 是 GA · DO new_classes · DO 非同步 KV storage API 當主介面 · DO state(現在叫 ctx)· ws.accept() + addEventListener(擋掉 hibernation)· Drizzle db.transaction() 於 D1 · Drizzle v1 的 schema 選項 / relations() / casing

placement.hint(不存在,實際是 mode / region / host / hostname)· Smart Placement 作用於 RPC 或 named entrypoint(只作用於 fetch)· wrangler dev --test-scheduled/__scheduled · Container instance type dev / 裸 standard · GPU container(不存在)· 說 Dynamic Workers 是 GA · 說 Dynamic Workflows 是「Workflows v2」· 說 Workers for Platforms 被取代 · subrequests(正確是 subRequests)· Snippets 搭配 bindings/secrets · Email「只能寄給已驗證地址」· cloudflare:email + mimetext 當主要寄信路徑 · Pipelines 的 "pipeline" binding key(已改 "stream")· 說 Pages 已 deprecated

2026-05-30 下架的 18 個模型 · 照抄 Cloudflare 自家 quickstart / AI SDK / JSON mode 範例(都印著死掉的 model ID)· stream: true 放第三個參數 · gateway.run() · Universal Endpoint · cf-cache-ttl / cf-skip-cache · 在 gateway.ai.cloudflare.com 把 CF token 放 Authorization · 說 Guardrails 支援 streaming · 把 MCP portal 歸給 AI Gateway · 說 Agents SDK 是 GA · agents/ai-chat-agent / agents/ai-react(import 即 throw)· server 端 onStateUpdate · AI SDK v4/v5 · workers-mcp · module-scope new McpServer() · mcp-handler(Vercel 的套件)

React Router AppLoadContext / context.cloudflare.env(v8 會 throw)· cloudflareDevProxy() · react-router-dom · Astro Astro.locals.runtime.* / Runtime<Env> / platformProxy / routes / cloudflareModules · hono/cloudflare-workersserveStatic · @cloudflare/next-on-pages(→ @opennextjs/cloudflare)· Lucia(已棄用)· OpenAuth(停更約 16 個月)

defineWorkersConfig / defineWorkersProject / poolOptions.workers · cloudflare:testenv / SELF · fetchMock · isolatedStorage / singleWorker · Vitest 2.x / 3.x · unstable_dev() · 直接用 Miniflare API 當預設 · 用 Query Builder 查 traces · OTel metrics 匯出(不支援)· 把 trace span 名稱當穩定契約 · 寫死 trace 價格(官方頁面互相矛盾)


附錄 B:版本鎖定基準(2026-07-27 查證)

Section titled “附錄 B:版本鎖定基準(2026-07-27 查證)”
wrangler 4.114.0
@cloudflare/vite-plugin 1.47.0
@cloudflare/vitest-pool-workers 0.18.8 (需 vitest ^4.1.0)
miniflare 4.20260722.0
create-cloudflare 2.70.14 (Astro template 已過時,勿用)
hono 4.12.32 (無 v5)
@hono/zod-validator 0.9.0
react-router / @react-router/* 8.3.0 (需 Node ≥22.22, Vite 7/8)
astro 7.1.3
@astrojs/cloudflare 14.1.4
drizzle-orm 0.45.2 (latest) / 1.0.0-rc.4 (rc) ← 必須先選線
drizzle-kit 0.31.10 / 1.0.0-rc.4
better-auth 1.6.25
@auth/core 0.41.3
jose 6.2.4
@cloudflare/workers-oauth-provider 0.8.2 (務必 >0.8.0)
agents 0.19.0 (0.x,非 GA)

附錄 C:待確認事項(發佈前需複查)

Section titled “附錄 C:待確認事項(發佈前需複查)”
  1. Trace 計費:官方兩個頁面分別寫 $0.60/M 與 $0.05/M。
  2. Pipelines 計費是否已啟動:changelog 與 pricing 頁說法不一致。
  3. D1 read replication 是否已 GA:文件仍標 beta,未見 GA 公告。
  4. Workers AI queueRequest:Batch 頁面有寫,但 workerd 的 AiOptions 型別裡沒有,TS 使用者可能需要 cast。
  5. drizzle-orm 1.0 stable 的發佈時間:無公開時程。
  6. drizzle-kit v1 與 wrangler d1 migrations apply 的目錄不相容:此結論來自反編譯已發佈的 CLI,非官方文件,發佈前務必用自己的 out/ 實測。