sell整合實戰
account_tree

前端、後端、資料庫是怎麼串起來的

一個瀏覽器、一個 Worker、一個資料庫。三個小元件,用 bindings(綁定)串在一起。只要看懂它們怎麼接,整個「整合實戰」章節就通了。

3要串接的層
1一行指令部署
0要管理的伺服器
330+供應它的城市
insights

我們到底要把什麼串起來?

幾乎每個網頁應用都在做三件事:把東西「呈現」給人看、執行「邏輯與規則」、以及「記住」資料。在 Cloudflare 上,這三件事分別對應到三個元件——瀏覽器(前端 front-end)、一個 Worker(你的後端 API)、以及一個資料庫(D1、KV、R2 或 Durable Objects)。這篇就是要給你一張「它們怎麼接」的心智地圖。

「前端(front-end)」指的是跑在使用者瀏覽器裡的那一部分——也就是使用者真正看到、點得到的 HTML、CSS 和 JavaScript。「後端(back-end)」則是跑在伺服器上的程式碼(這裡就是 Worker),使用者不會直接看到它;它負責「思考」並跟資料庫溝通。「資料庫(database)」就是把資料存起來的地方,讓資料在這次請求結束後還活著。

restaurant

把它想成一間餐廳

瀏覽器是「用餐區」,客人坐在那裡點餐;Worker 是「廚房」,收到點單後決定怎麼處理;資料庫則是放食材的「儲藏室」。客人不會自己跑進儲藏室——他跟廚房點餐,廚房再去儲藏室拿食材。

schema大局觀:全端應用是怎麼拼起來的

載入頁面

fetch /api

查詢

資料

JSON

使用者

瀏覽器(前端)

靜態資源:HTML/CSS/JS

Worker(後端 API)

資料庫:D1/KV/R2

注意從瀏覽器出發有兩種不同的箭頭:一種去載入組成頁面的靜態檔案(也就是「外觀」);另一種是 API 呼叫,向 Worker 要最新的資料(也就是「內容」)。把這兩件事分開,正是整個模型的核心。

account_tree

三層各自的職責

每一層都有一個明確的職責。把職責混在一起,是初學者最常犯的錯(例如把資料庫密碼寫在前端程式碼裡,結果任何人都看得到)。請像下面這樣,把責任分清楚:

devices

前端 — 瀏覽器

負責畫出畫面(UI)並回應點擊。它不掌握任何機密。它用 fetch() 向後端要資料,再把結果顯示出來。

dns

後端 — Worker

負責接收請求、套用你的規則與安全檢查、保管機密,而且是唯一被允許碰資料庫的那一層。

database

資料層 — 資料庫

負責在不同請求之間「記住」資料。在 Cloudflare 上可以是 D1(SQL)、KV(鍵值)、R2(檔案)或 Durable Objects(即時狀態)。

lock

為什麼要這樣分

瀏覽器裡的任何東西都是公開的——使用者打開開發者工具就看得到。所以機密和資料庫存取一定要留在 Worker,絕不能放在前端。

schema把三層疊起來看

fetch

讀 / 寫

JSON

前端:瀏覽器(HTML/CSS/JS)

後端:Worker(API)

資料層:D1 / KV / R2 / Durable Objects

bolt

一個 Worker 可以身兼兩職

在 Cloudflare 上,常常用「同一個 Worker」同時供應靜態前端檔案、又執行後端 API。它們住在同一個專案,但邏輯上仍然分開:大部分路徑給靜態檔案,像 /api/* 這類路徑則交給 API 邏輯。

swap_vert

跟著一個請求,從頭走到尾

理解全端應用最快的方法,就是「跟著一次點擊走一遍」。想像一個頁面上有一顆「載入待辦」按鈕。下面就是使用者按下去時,一步一步到底發生了什麼事。

schema點擊 → fetch → Worker → 資料庫 → JSON 回傳
"資料庫""Worker""瀏覽器""資料庫""Worker""瀏覽器"使用者點擊按鈕fetch GET /api/todosSELECT id, title FROM todos資料列JSON 回應把清單畫到畫面上

每一步在做什麼

  • 點擊:瀏覽器的 JavaScript 偵測到按鈕被按下,呼叫 fetch()。
  • fetch GET /api/todos:一個 HTTP 請求離開瀏覽器,被導向你的 Worker。
  • SELECT ...:Worker 向資料庫要它需要的那些列(rows)。
  • 資料列:資料庫把符合的資料交還給 Worker。
  • JSON 回應:Worker 把資料轉成 JSON(一種簡單的文字格式)回傳。
  • 畫出來:瀏覽器收到 JSON 後更新頁面——完全不用整頁重新載入。
data_object

為什麼用 JSON?

JSON(JavaScript Object Notation,JavaScript 物件表示法)是一種輕量的文字格式,Worker 和瀏覽器天生都看得懂。後端送的是「資料」而不是 HTML,所以前端可以自由決定要怎麼把它呈現出來。

cable

Bindings:Worker 怎麼接到儲存

Worker 連資料庫的方式,不像舊式伺服器那樣靠「密碼 + 連線字串」。取而代之的是宣告一個 binding(綁定)——一條有名字、又安全的連線,由 Cloudflare 幫你接好。在程式碼裡,這個 binding 會以 env 物件上的屬性出現,例如 env.DB。

schema一個 Worker,多種綁定

接上

env.DB

env.CACHE

env.BUCKET

env.ROOM

wrangler.toml 綁定設定

Worker(後端)

D1(SQL 資料庫)

KV(鍵值儲存)

R2(檔案儲存)

Durable Objects(即時狀態)

table_rows

D1 → env.DB

一個 SQL 資料庫,適合有結構、有關聯的資料,例如使用者和訂單。用 SELECT / INSERT / UPDATE 查詢。

key

KV → env.CACHE

一個鍵值(key-value)儲存,適合常常被讀取的簡單查找,例如設定值或快取頁面。全球讀取都超快。

folder

R2 → env.BUCKET

物件儲存,適合大檔案——圖片、影片、PDF、備份。就像雲端上的資料夾,而且沒有流量輸出費用。

hub

Durable Objects → env.ROOM

一個單一、一致的地方來保存即時狀態——很適合聊天室、遊戲大廳,或多位使用者共用的計數器。

settings

綁定名稱由你自己取

DB、CACHE、BUCKET、ROOM 都只是你在 wrangler.toml 裡自己取的名字。你把 binding 名稱寫成什麼,程式碼裡的 env 上就會出現一模一樣的名字。取清楚一點,你就不會搞混。

construction

親手把它串起來

下面是三層一起運作的「最小版本」:一段會呼叫 fetch 的前端、一個從 D1 回傳 JSON 的 Worker、把它們綁在一起的 wrangler.toml,以及建立資料的 SQL。把這幾段放進同一個專案,你就有一個真正的全端應用了。

  1. 1. 前端(跑在瀏覽器裡)

    純 JavaScript,點擊時呼叫你的 API,再把結果畫出來。不用任何框架就能看懂這個概念。

    html
    <!-- public/index.html -->
    <button id="load">Load todos</button>
    <ul id="list"></ul>
    
    <script>
      async function loadTodos() {
        // Ask the Worker (back-end) for data
        const res = await fetch("/api/todos");
        const todos = await res.json();
        // Paint the result into the page
        document.querySelector("#list").innerHTML =
          todos.map((t) => `<li>${t.title}</li>`).join("");
      }
      document.querySelector("#load").addEventListener("click", loadTodos);
    </script>
  2. 2. 後端 Worker(回傳 JSON)

    一般路徑它供應靜態檔案;遇到 /api/todos 時,它透過 env.DB 讀取 D1,再回傳 JSON。注意:使用者的請求從不直接碰資料庫——只有 Worker 會。

    js
    // src/index.js
    export default {
      async fetch(request, env, ctx) {
        const url = new URL(request.url);
        if (url.pathname === "/api/todos") {
          // env.DB is the D1 binding from wrangler.toml
          const { results } = await env.DB
            .prepare("SELECT id, title FROM todos")
            .all();
          return Response.json(results);
        }
        // Everything else is served as a static asset
        return env.ASSETS.fetch(request);
      },
    };
  3. 3. wrangler.toml(接好綁定)

    這個設定檔告訴 Cloudflare:你的 Worker 進入檔在哪、靜態檔案放哪、以及要把哪個資料庫以 env.DB 的名義開放出來。

    toml
    name = "my-fullstack-app"
    main = "src/index.js"
    compatibility_date = "2025-01-01"
    
    # Serve the front-end from ./public, exposed as env.ASSETS
    [assets]
    directory = "./public"
    binding = "ASSETS"
    
    # Bind a D1 database; reach it in code as env.DB
    [[d1_databases]]
    binding = "DB"
    database_name = "my-app-db"
    database_id = "<paste-your-database-id>"
  4. 4. 資料層(建立資料表)

    把這段 SQL 跑一次,建立 todos 資料表並塞幾筆資料,這樣你的 /api/todos 端點才有東西可以回傳。

    sql
    CREATE TABLE IF NOT EXISTS todos (
      id INTEGER PRIMARY KEY,
      title TEXT NOT NULL
    );
    
    INSERT INTO todos (title) VALUES
      ('Learn the full-stack model'),
      ('Wire a Worker to D1');
  5. 5. 先在本機跑,再部署

    wrangler dev 會在本機把所有東西跑起來,網址是 http://localhost:8787。覺得 OK 後,wrangler deploy 一次就把三層全部部署到 Cloudflare 的全球網路上。

    bash
    npx wrangler d1 execute my-app-db --local --file=./schema.sql
    npx wrangler dev
    npx wrangler deploy
north_east

下一步:完整 CRUD

這篇只示範「讀取」資料。如果還想從瀏覽器「新增、更新、刪除」資料,請接著看姊妹篇〈前端 ↔ Worker ↔ D1:完整 CRUD 串接〉。

school

重點術語一次看懂

language

前端(Front-end)

跑在使用者瀏覽器裡的程式碼:他們看到、會互動的 HTML、CSS 和 JavaScript。

dns

後端(Back-end)

跑在伺服器上的程式碼(這裡是 Worker),在使用者看不到的地方處理邏輯、安全和資料庫存取。

http

API

Application Programming Interface(應用程式介面)——前端用來向後端要東西的一組網址(例如 /api/todos)。

sync

fetch()

瀏覽器內建的函式,用來向某個網址發 HTTP 請求並讀取回應——這就是前端跟 API 對話的方式。

cable

Binding(綁定)

從 Worker 連到其他服務(D1、KV、R2、Durable Objects)的一條有名字、又安全的連線,透過 env 物件存取。

tune

wrangler.toml

設定檔,你在裡面替 Worker 取名字並宣告它的 bindings。你執行或部署時,Wrangler 會讀取它。

data_object

JSON

一種輕量的資料文字格式。後端通常用 JSON 回應,這樣前端就能輕鬆讀取。

storage

資料庫(Database)

資料被存放的地方,讓它在不同請求之間還活著。在 Cloudflare 上有:D1、KV、R2、Durable Objects。

tips_and_updates

常見陷阱與小提示

vpn_key

機密絕不能放在前端

API 金鑰、資料庫憑證、權杖(token)只能放在 Worker。任何送到瀏覽器的東西,任何人用開發者工具都讀得到。請用 Wrangler 的機密功能(wrangler secret put)把機密留在伺服器端。

初學者常踩的雷

  • CORS 錯誤:如果前端和 API 在同一個 Worker 上,通常就完全避開了——用同一個來源(origin)供應兩者是最簡單的做法。
  • 忘了 await:fetch() 和 D1 查詢都是非同步的;一定要 await,不然你拿到的會是 Promise 而不是資料。
  • 想回 JSON 卻回了 HTML:用 Response.json(data),前端才能乾淨地呼叫 res.json()。
  • 綁定名稱對不上:wrangler.toml 裡的名字要和你在 env 上讀的一致(env.DB 就要有 binding = "DB")。
  • 改到本機還是遠端資料庫:--local 動的是你電腦上的副本;拿掉它(或用 --remote)才會改到已部署的資料庫。
savings

起步成本很低

Workers 免費方案每天有 10 萬次請求,D1 也有大方的免費額度——足夠你開發、學習一個全端應用,完全不用先付費。正式上線前,記得到官方文件確認最新的限制數字。