cf-todo-demo

Cloudflare Workers · D1 · R2

一個 Worker,
四種身分。

你正在看的這一頁、等一下輸入的待辦、上傳的那張圖,都由同一支 Worker 決定去向。 下面這條軌跡記錄每一次真實請求:它經過哪些綁定、各花幾毫秒、在哪個節點執行。

Edge Trace

節點 —

    在下方 Demo 操作,這裡會即時記錄每一次請求。

    路徑

    四條路徑,一支 Worker

    wrangler.jsonc 裡只寫了一行 run_worker_first: ["/api/*"]。 這一行就是下面所有分岔的來源 —— 符合的走 Worker,不符合的直接由邊緣節點送出檔案。

    Demo

    試一下

    每個動作都是一次真實請求。做完馬上往上看 Edge Trace, 對照這次走的是 D1、R2,還是兩個都走。

    綁定

    三個綁定,三行程式碼

    綁定(binding)是 Worker 取用雲端資源的方式。在 wrangler.jsonc 宣告, 在程式裡就變成 env 上的一個物件 —— 沒有連線字串,也沒有金鑰要保管。

    Static Assets

    env.ASSETS

    把 public/ 整個目錄放上 Cloudflare 的邊緣網路。 HTML、CSS、JS 直接從離使用者最近的節點送出。

    // wrangler.jsonc
    "assets": {
      "directory": "./public",
      "run_worker_first": ["/api/*"]
    }

    單檔 25 MiB · 免費方案 20,000 個檔案

    D1

    env.DB

    Cloudflare 託管的 SQLite。適合存結構化、查得到、量不大的資料 —— 這裡存的是待辦文字與完成狀態。

    await env.DB
      .prepare('SELECT * FROM todos WHERE user_id = ?')
      .bind(userId)
      .all();

    免費方案 500 MB · 單列上限 2 MB

    R2

    env.BUCKET

    相容 S3 的物件儲存,沒有流量傳出費用。 適合圖片、影片、備份 —— 任何不該塞進資料庫的東西。

    await env.BUCKET.put(key, file, {
      httpMetadata: {
        contentType: file.type
      }
    });

    單物件 5 TiB · 物件鍵長度 1024 bytes

    部署

    從空資料夾到線上網址

    以下五步有先後順序:資源要先存在,設定檔才填得完;設定檔填完,Cloudflare 才接得上你的 repo。

    1. 01

      建立 D1 與 R2

      npx wrangler d1 create todo-db
      npx wrangler r2 bucket create todo-images

      R2 需要先在 Cloudflare 後台啟用(要綁付款方式,免費額度仍然免費)。D1 不用。

    2. 02

      把 database_id 填回設定檔

      // wrangler.jsonc
      "d1_databases": [{
        "binding": "DB",
        "database_name": "todo-db",
        "database_id": "上一步印出來的那串 UUID"
      }]

      R2 沒有 id,用 bucket 名稱對應就行。 不想把 UUID 寫進檔案的話,第 05 步的組建變數也可以代勞。

    3. 03

      建立資料表

      npm run db:remote
      # 等同 npx wrangler d1 migrations apply DB --remote

      少了 --remote 就只會套用到本機那份 SQLite,線上依然是空的 —— 這是最常見的錯誤。 指令裡的 DB 是 binding 名稱,不是資料庫名稱,所以你改資料庫名字時這行不用跟著改。

    4. 04

      推上 GitHub

      git init && git add . && git commit -m "init"
      git remote add origin <你的 repo>
      git push -u origin main

      .gitignore 已經擋掉 .wrangler/ 與 .dev.vars。

    5. 05

      在 Cloudflare 接上 repo

      後台 Workers & Pages → Create → Workers → Import a repository, 選好 repo 後 build 指令留空, 部署指令改成 npm run deploy、版本指令改成 npm run upload。 接好之後,每次 push 到 main 都會自動部署。

      這兩個指令一定要改,是這裡最容易漏掉的一步。Cloudflare 預設的 npx wrangler deploy 會直接呼叫 wrangler,不觸發 npm 的 predeploy 掛勾 —— 設定檢查與組建變數注入都不會執行, 結果就是變數明明設好了,部署卻還是失敗在 database_id。

      同一頁的 Build variables and secrets 可以設 D1_DATABASE_ID、D1_DATABASE_NAME、R2_BUCKET_NAME、 CF_WORKER_NAME、GOOGLE_CLIENT_ID, 部署時會自動填進 wrangler.jsonc,repo 裡就不必放自己的值。

      GOOGLE_CLIENT_ID 要走這條路而不是後台的 Variables and Secrets(執行時那一區)—— 只要 wrangler.jsonc 的 vars 還留著那一行, 每次部署都會把後台設的值蓋回去。