CDN 快取策略設計:讓你的網站快到飛起來
CDN 快取策略設計:讓你的網站快到飛起來
CDN(Content Delivery Network,內容傳遞網路)是現代 Web 效能優化的核心工具。一個設計良好的快取策略,可以讓靜態資源的回應時間從幾百毫秒降到幾毫秒,大幅改善使用者體驗。這篇文章系統性地介紹 CDN 快取策略的設計思路與實作細節。
CDN 的基本運作原理
使用者 → CDN 邊緣節點(快取命中)→ 直接回傳
使用者 → CDN 邊緣節點(快取未命中)→ 源站 → 快取並回傳CDN 在全球各地部署邊緣節點,使用者的請求會被路由到最近的節點。如果該節點有快取,就直接回傳;否則才回源站取得並快取。
HTTP 快取標頭
快取控制的核心是 HTTP 標頭:
Cache-Control
# 快取 1 年(適用於有 hash 的靜態資源)
Cache-Control: public, max-age=31536000, immutable
# 快取 1 小時,允許過期後驗證
Cache-Control: public, max-age=3600, stale-while-revalidate=86400
# 不快取(適用於 API 回應)
Cache-Control: no-store
# 每次都驗證(適用於 HTML 頁面)
Cache-Control: no-cacheETag 與 Last-Modified
# 伺服器回應
ETag: "abc123"
Last-Modified: Wed, 01 Jan 2025 00:00:00 GMT
# 客戶端重新驗證
If-None-Match: "abc123"
If-Modified-Since: Wed, 01 Jan 2025 00:00:00 GMT
# 如果內容未變更,伺服器回傳 304
HTTP/1.1 304 Not Modified不同資源類型的快取策略
靜態資源(有 content hash)
最佳策略是永久快取。現代打包工具(Vite、Webpack)會在檔名加入內容 hash:
main.abc123.js → 一旦發布就不會變動
style.def456.css → 有更新就產生新 hash,新 URL# Nginx 設定
location ~* \.(js|css|png|jpg|webp|woff2)$ {
# 符合 hash 模式的靜態資源
if ($uri ~* "\.[a-f0-9]{8,}\.(js|css)$") {
add_header Cache-Control "public, max-age=31536000, immutable";
}
}HTML 頁面
HTML 通常包含對靜態資源的引用,不應長期快取:
location ~* \.html$ {
add_header Cache-Control "public, no-cache";
add_header ETag $request_id;
}API 回應
依照資料的更新頻率決定:
// Express.js 範例
app.get('/api/products', (req, res) => {
// 產品列表:快取 5 分鐘,允許過期後繼續服務
res.set('Cache-Control', 'public, max-age=300, stale-while-revalidate=3600');
res.json(products);
});
app.get('/api/stock/:id', (req, res) => {
// 庫存資訊:不快取,需要即時
res.set('Cache-Control', 'no-store');
res.json(stock);
});Cloudflare 快取設定
Cloudflare 是最普及的 CDN 服務,提供靈活的快取規則:
Page Rules / Cache Rules
# 靜態資源:快取等級設為 Cache Everything
URL 模式: *.example.com/assets/*
快取等級: Cache Everything
邊緣快取 TTL: 1 個月
# API:繞過快取
URL 模式: *.example.com/api/*
快取等級: BypassCloudflare Workers 精細控制
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
// 靜態資源:使用 CDN 快取
if (url.pathname.startsWith('/assets/')) {
const response = await fetch(request, {
cf: {
cacheTtl: 86400 * 365,
cacheEverything: true,
},
});
return response;
}
// API:加上版本標頭,短暫快取
if (url.pathname.startsWith('/api/public/')) {
const response = await fetch(request, {
cf: {
cacheTtl: 60,
cacheEverything: true,
},
});
return response;
}
return fetch(request);
}Cache Purge(清除快取)
當內容更新時,需要主動清除 CDN 快取:
# Cloudflare API:清除特定 URL
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"files": ["https://example.com/api/products"]}'
# 清除所有快取(謹慎使用)
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"purge_everything": true}'在 CI/CD 中自動清除
# .github/workflows/deploy.yml
- name: Deploy
run: npm run build && rsync -av dist/ server:/var/www/
- name: Purge CDN Cache
run: |
curl -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/purge_cache" \
-H "Authorization: Bearer $CF_API_TOKEN" \
-H "Content-Type: application/json" \
--data '{"files": ["https://example.com/"]}'
env:
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}stale-while-revalidate 策略
這是一個非常實用的快取策略,讓使用者不需要等待重新驗證:
Cache-Control: max-age=60, stale-while-revalidate=3600- 第 0-60 秒:直接用快取,不詢問伺服器
- 第 61-3660 秒:回傳過期的快取(不讓使用者等),同時在背景更新
- 超過 3660 秒:等待伺服器回應
快取命中率監控
// 在回應標頭中加入快取狀態
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const cacheStatus = res.getHeader('cf-cache-status') ||
res.getHeader('x-cache') || 'UNKNOWN';
metrics.increment('cdn.request', {
cache_status: cacheStatus,
path: req.path,
status: res.statusCode,
});
});
next();
});快取策略決策樹
是否包含個人化資料?
├── 是 → Cache-Control: private 或 no-store
└── 否
├── 是否是靜態資源(有 hash)?
│ ├── 是 → max-age=31536000, immutable
│ └── 否
│ ├── 更新頻率?
│ ├── 即時 → no-store
│ ├── 分鐘級 → max-age=60, stale-while-revalidate
│ └── 小時/天級 → max-age=3600+, no-cache總結
良好的 CDN 快取策略能大幅提升網站效能,降低源站負載。核心原則是:靜態資源永久快取,HTML 不快取或短暫快取,API 根據資料時效性決定。搭配 content hash 的靜態資源和自動化的 cache purge 流程,可以在效能與即時性之間取得最佳平衡。
分享這篇文章