sell整合實戰
cached

快取是怎麼運作的(命中、未命中、重新驗證)

看清楚邊緣節點何時秒回、何時回源、何時把過期的複本刷新。

330+提供快取的邊緣城市
2兩次載入由 MISS 變 HIT
0命中時的回源次數
5要懂的 cf-cache-status 狀態
insights

我們要看懂什麼?

每當瀏覽器向 Cloudflare 要一個檔案,邊緣節點(edge node,離訪客最近的快取伺服器)都會跑同一個快速判斷:我手上有沒有還新鮮的複本?有的話,它在幾毫秒內就回覆(快取命中 HIT)。沒有的話,它就去你的來源伺服器(origin,你真正放網站的那台主機)或 Worker 抓取,視情況把回應存起來,再送出(快取未命中 MISS)。這篇用圖把整個生命週期畫出來,讓你一眼看懂。

schema快取判斷流程(單一請求)

請求抵達邊緣節點

快取裡有且還新鮮?

由快取直接送出(HIT)

回源抓取 / 執行 Worker

可以快取嗎?

依 Cache-Control / TTL 儲存

不快取直接送出(DYNAMIC / BYPASS)

送給訪客(MISS)

kitchen

把它想成一台冰箱

邊緣快取就是你家冰箱,來源伺服器則是超市。牛奶在冰箱裡又還沒過期(TTL)就直接喝(HIT);冰箱裡沒有就跑一趟超市(MISS);剛好過期一點點,就先聞一下確認再決定要不要買新的(重新驗證 revalidate)。

school

圖上這些名詞的意思

在看流程圖之前,先認識五個一直出現的名詞。每一個都對應到下面圖裡的某個方框或箭頭。

hub

邊緣快取(edge cache)

Cloudflare 離訪客很近的伺服器,存著你回應的複本,能直接回覆而不用打擾你的來源伺服器。

dns

來源伺服器(origin)

你真正產生回應的伺服器或 Worker。只有 MISS 或要重新驗證時,邊緣節點才會回到這裡。

timer

TTL(存活時間)

Time To Live,快取複本被當成新鮮的秒數。由 Cache-Control 的 max-age / s-maxage 或快取規則(Cache Rule)決定。

schedule

新鮮 vs 過期(fresh / stale)

在 TTL 內的複本是新鮮的,可立即送出;超過 TTL 就變過期(stale),必須重新驗證或重新抓取。

mop

清除 / 失效(purge)

在 TTL 還沒到之前就手動把快取複本踢掉——可依網址、標籤或全部清除——讓下一個請求重新建立。

fingerprint

快取鍵(cache key)

邊緣節點用來查複本的依據,預設就是完整網址。兩個不同網址就是兩筆不同的快取。

swap_vert

命中 vs 未命中 vs 重新驗證

同一個網址,會因為邊緣節點手上有什麼而表現不同。這張時序圖示範同一個 /logo.png 被請求三次:第一次是冷的(MISS)、接著是熱的(HIT)、最後是 TTL 過期之後(重新驗證)。

schema三次請求,三種結果
"來源 / Worker""邊緣快取""瀏覽器""來源 / Worker""邊緣快取""瀏覽器"第一次造訪,尚未快取TTL 內,複本還新鮮超過 TTL,複本過期GET /logo.png快取是空的,回源抓取200 加上 Cache-Control max-agecf-cache-status MISSGET /logo.pngcf-cache-status HITGET /logo.png用 If-None-Match 重新驗證304 Not Modifiedcf-cache-status REVALIDATED
verified

重新驗證很省頻寬

重新驗證時,邊緣節點用驗證碼(ETag / Last-Modified)去問「這個有沒有變?」。回 304 Not Modified 代表它可以繼續用手上那份複本,只要把計時器刷新就好,不必整份重新下載。

timeline

TTL 隨時間變化:新鮮、過期、重新驗證

每份快取複本都附帶一個計時器。從被儲存的那一刻起,它在 max-age 用完前都算 FRESH(新鮮),之後變成 STALE(過期)。過期後的下一個請求才會觸發重新驗證,而驗證結果會把計時器重設回 FRESH。

schema一份快取複本的一生

已儲存(t = 0)

max-age 內為 FRESH

到達 TTL

超過 max-age 變 STALE

下一個請求觸發重新驗證

304:保留複本,重設為 FRESH

200:存入新複本,重設為 FRESH

bolt

stale-while-revalidate(過期照送、背景刷新)

用 Cache-Control: max-age=60, stale-while-revalidate=600 時,邊緣節點可以先把過期的複本立刻送給使用者,同時在背景回源刷新。訪客完全不用等重新驗證。

fact_check

看懂 cf-cache-status

Cloudflare 會用一個叫 cf-cache-status 的回應標頭(response header),告訴你這個請求走了流程圖的哪一條分支。下面是你最常遇到的幾個值。

check_circle

HIT(命中)

邊緣快取裡有新鮮的複本,立刻送出。完全不用回源,是最快也最省的結果。

cancel

MISS(未命中)

這個鍵沒有快取,所以邊緣節點回源抓取,若允許就存起來給下次用。

history

EXPIRED(過期)

原本有複本,但 TTL 到了,所以邊緣節點重新驗證或回源抓一份新的。

auto_mode

DYNAMIC(動態)

內容被視為動態、預設不適合快取,所以每個請求都回源。

block

BYPASS(略過)

刻意略過快取——可能是某條快取規則、no-store 標頭,或設定要求邊緣節點不要快取。

verified

REVALIDATED(已重新驗證)

過期複本拿去跟來源核對(ETag / If-None-Match),來源回 304,於是同一份複本被重複使用。

construction

動手控制:設標頭 + 驗證

上面這一切,都是用來源或 Worker 送出的一個 HTTP 標頭來操控:Cache-Control。max-age 是瀏覽器 TTL;s-maxage 是邊緣(共用快取)TTL,在 Cloudflare 會蓋過 max-age。

httpCache-Control 標頭配方
# Static asset: 1 hour in browsers, 1 day on the edge
Cache-Control: public, max-age=3600, s-maxage=86400

# Serve stale instantly, refresh in the background for 10 min
Cache-Control: public, max-age=60, stale-while-revalidate=600

# Per-user / logged-in page: never cache anywhere
Cache-Control: private, no-store
jsworker.js — 設定 Cache-Control
export default {
  async fetch(request) {
    const body = JSON.stringify({ hello: "world" });
    return new Response(body, {
      headers: {
        "Content-Type": "application/json",
        // Browser keeps it 1h; Cloudflare edge keeps it 1 day
        "Cache-Control": "public, max-age=3600, s-maxage=86400"
      }
    });
  }
};
  1. 送出標頭

    部署你的 Worker,或設定來源伺服器,讓可快取的回應帶上 public 的 Cache-Control 並設定 s-maxage。

  2. 連續請求兩次

    用 curl -sI 跑兩次。第一次通常是 MISS(冷的),第二次從同一個邊緣城市應該變成 HIT(熱的)。

    bash
    # -s silent, -I headers only; look at cf-cache-status
    curl -sI https://example.com/logo.png | grep -i cf-cache-status
    # 1st run -> cf-cache-status: MISS
    # 2nd run -> cf-cache-status: HIT
  3. 更新後清除快取

    在 TTL 還沒到就改了檔案?清除它,讓下一個請求重建一份新的複本。

    bash
    # Purge a single URL via the API
    curl -X POST \
      "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
      -H "Authorization: Bearer $CF_API_TOKEN" \
      -H "Content-Type: application/json" \
      --data '{"files":["https://example.com/logo.png"]}'
compare_arrows

CDN 快取 vs KV 快取

在 Cloudflare,「快取」這個詞常指兩種很不一樣的東西。CDN 快取(也就是本篇)是自動的、以網址為鍵;Workers KV 則是應用層快取,由你自己的程式以 key 讀寫。兩者解決的是不同的問題。

schema請求會落在哪一種快取

進來的請求

靜態且大家都一樣?

CDN 邊緣快取:自動、以網址為鍵

執行 Worker 邏輯

是可重複使用的運算結果?

Workers KV:在程式中以 key 讀寫

來源伺服器 / 資料庫

public

CDN 快取

快取的是整個 HTTP 回應,以網址為鍵,所有使用者共用。由 Cache-Control 與快取規則控制。最適合靜態資源與頁面。

key

KV 快取

你用自己挑的 key 存任意的值,在 Worker 程式裡讀寫。適合存運算後的 API 結果、設定,與以 key 區分的資料。

auto_awesome

自動 vs 手動

內容一經代理,CDN 快取就自動發生。KV 在你的程式呼叫 KV.get、KV.put 之前什麼都不做——邏輯由你掌控。

layers

兩者可以併用

Worker 可以先讀 KV 組出回應,再送出 Cache-Control 讓 CDN 把這個回應快取在邊緣——兩層快取,一條快路。

tips_and_updates

陷阱與小提示

lock_person

千萬別快取每位使用者專屬頁面

如果已登入的後台被公開快取,某位使用者就可能看到別人的資料。針對個人化或需驗證的回應,一律送出 Cache-Control: private, no-store。

  • 回 200 但沒有 Cache-Control,常會變成 DYNAMIC——設好標頭才會被快取。
  • cf-cache-status 是各邊緣據點各自記錄,所以新城市出現一次 MISS 很正常。
  • 在檔名加版本(app.v2.js),更新就會產生新的快取鍵,不必特地清除。
  • 查詢字串預設會改變快取鍵——/a?x=1 和 /a?x=2 是分開快取的。
  • 善用 stale-while-revalidate,讓使用者永遠不必等重新驗證的來回。