跳至主要內容
Skip to content

Cache-Control 全參數解析

Cache-Control 是 HTTP 快取的核心標頭。本篇將詳細解析每個指令的含義與使用場景。


一、 基本語法

1.1 格式

http
Cache-Control: directive1, directive2, directive3

1.2 分類

類別指令
可快取性public, private, no-cache, no-store
過期時間max-age, s-maxage, max-stale, min-fresh
重新驗證must-revalidate, proxy-revalidate
其他no-transform, immutable

二、 可快取性指令

2.1 public

允許任何快取(包括 CDN)儲存回應:

http
Cache-Control: public, max-age=86400

適用場景:

  • 完全公開的資源
  • 所有用戶看到相同內容

2.2 private

只允許瀏覽器快取,禁止共享快取(如 CDN):

http
Cache-Control: private, max-age=3600

適用場景:

  • 用戶專屬內容(個人資料、購物車)
  • 包含敏感資訊的回應
javascript
// 個人資料
app.get("/api/profile", (req, res) => {
  res.set("Cache-Control", "private, max-age=300");
  res.json(userProfile);
});

2.3 no-cache

允許快取,但每次使用前必須驗證

http
Cache-Control: no-cache

> `no-cache` 不是「不快取」!而是「每次都要驗證」。

2.4 no-store

完全禁止儲存,每次都要重新下載:

http
Cache-Control: no-store

適用場景:

  • 極度敏感的資料(銀行交易、密碼)
  • 需要即時更新的內容
javascript
// 銀行交易
app.get("/api/transactions", (req, res) => {
  res.set("Cache-Control", "no-store");
  res.json(transactions);
});

2.5 比較表

指令允許儲存需要驗證適用場景
public✅ 所有快取公開資源
private✅ 僅瀏覽器用戶專屬
no-cache✅ 每次需要驗證
no-store-敏感資料

三、 過期時間指令

3.1 max-age

快取有效期(秒):

http
Cache-Control: max-age=3600    # 1 小時
Cache-Control: max-age=86400   # 1 天
Cache-Control: max-age=31536000 # 1 年

3.2 s-maxage

專門給共享快取(CDN)使用,優先級高於 max-age:

http
Cache-Control: public, max-age=60, s-maxage=600
  • 瀏覽器:60 秒
  • CDN:600 秒

3.3 max-stale

客戶端願意接受過期的快取:

http
# 請求標頭
Cache-Control: max-stale=3600

表示願意接受過期不超過 1 小時的回應。

3.4 min-fresh

要求回應至少還有指定時間的新鮮度:

http
# 請求標頭
Cache-Control: min-fresh=600

只接受至少還有 10 分鐘有效期的快取。


四、 重新驗證指令

4.1 must-revalidate

過期後必須向伺服器驗證,不能使用過期快取:

http
Cache-Control: max-age=3600, must-revalidate

如果伺服器無法連線,直接返回錯誤,而不是使用過期快取。

4.2 proxy-revalidate

與 must-revalidate 類似,但只對共享快取生效:

http
Cache-Control: max-age=3600, proxy-revalidate

4.3 stale-while-revalidate

允許在背景重新驗證時使用過期快取:

http
Cache-Control: max-age=60, stale-while-revalidate=3600

優點:用戶不用等待,體驗更好。

4.4 stale-if-error

伺服器錯誤時使用過期快取:

http
Cache-Control: max-age=3600, stale-if-error=86400

如果重新驗證時伺服器返回 5xx 錯誤,可以使用最多 24 小時前的過期快取。


五、 其他指令

5.1 no-transform

禁止中間代理修改回應:

http
Cache-Control: no-transform

防止代理:

  • 壓縮圖片
  • 轉換編碼
  • 修改內容

5.2 immutable

表示資源永遠不會變更:

http
Cache-Control: max-age=31536000, immutable

效果:即使強制刷新也不會重新驗證

適用場景:

  • 帶 hash 的靜態資源
  • app.abc123.js

六、 常見組合

6.1 帶 hash 的靜態資源

http
Cache-Control: public, max-age=31536000, immutable
  • 1 年快取
  • CDN 可快取
  • 強制刷新也不驗證

6.2 HTML 文件

http
Cache-Control: no-cache

http
Cache-Control: max-age=0, must-revalidate

每次都驗證,確保獲取最新版本。

6.3 API 回應

http
# 公開 API,短期快取
Cache-Control: public, max-age=60

# 私有 API
Cache-Control: private, max-age=300

# 敏感 API
Cache-Control: no-store

6.4 CDN 優化

http
Cache-Control: public, max-age=60, s-maxage=86400, stale-while-revalidate=600
  • 瀏覽器:1 分鐘
  • CDN:1 天
  • 過期時用戶不用等

七、 Express 實作

7.1 中介軟體

javascript
function cacheControl(options) {
  const {
    maxAge = 0,
    sMaxage,
    isPublic = false,
    noCache,
    noStore,
    immutable,
  } = options;

  return (req, res, next) => {
    const directives = [];

    if (noStore) {
      directives.push("no-store");
    } else if (noCache) {
      directives.push("no-cache");
    } else {
      directives.push(isPublic ? "public" : "private");
      directives.push(`max-age=${maxAge}`);

      if (sMaxage !== undefined) {
        directives.push(`s-maxage=${sMaxage}`);
      }

      if (immutable) {
        directives.push("immutable");
      }
    }

    res.set("Cache-Control", directives.join(", "));
    next();
  };
}

// 使用
app.use(
  "/assets",
  cacheControl({
    maxAge: 31536000,
    isPublic: true,
    immutable: true,
  })
);

app.use("/api", cacheControl({ noCache: true }));

7.2 按路由設定

javascript
// 靜態資源
app.get("/assets/*", (req, res, next) => {
  res.set("Cache-Control", "public, max-age=31536000, immutable");
  next();
});

// HTML
app.get("*.html", (req, res, next) => {
  res.set("Cache-Control", "no-cache");
  next();
});

// 敏感 API
app.get("/api/account", (req, res) => {
  res.set("Cache-Control", "no-store");
  res.json(account);
});

八、 Nginx 配置

nginx
# 帶 hash 的靜態資源
location ~* \.[a-f0-9]{8}\.(js|css|png|jpg|gif)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

# 一般靜態資源
location ~* \.(js|css|png|jpg|gif)$ {
    add_header Cache-Control "public, max-age=86400";
}

# HTML
location ~* \.html$ {
    add_header Cache-Control "no-cache";
}

# API
location /api/ {
    add_header Cache-Control "no-cache";
}

總結

指令說明常見場景
public允許所有快取CDN 資源
private只允許瀏覽器用戶資料
no-cache每次驗證HTML
no-store禁止儲存敏感資料
max-age有效期所有資源
s-maxageCDN 有效期CDN 優化
immutable永不變更帶 hash 檔案
stale-while-revalidate背景更新效能優化

> **黃金法則**:

  • 帶 hash → max-age=1y, immutable
  • HTML → no-cache
  • API → 根據敏感度選擇

進階挑戰

  1. 設計一個完整的快取策略,區分不同類型的資源。
  2. 測試 stale-while-revalidate,觀察背景更新行為。
  3. 研究各瀏覽器對 immutable 的支援程度。

延伸閱讀與資源