Skip to main content

網頁的快取機制是怎麼運作的?

什麼是網頁快取?

網頁快取(Caching)是指瀏覽器或伺服器將網頁資源(如 HTML 文件、圖片、CSS、JavaScript 檔案等)儲存在本地或中間層,以減少重複請求、加快載入速度並降低伺服器負擔的技術。快取機制可以讓用戶在重複訪問網頁時,快速取得資源,而不需要每次都從伺服器下載。

快取主要分為以下幾種類型:

  1. 瀏覽器快取(Browser Cache):資源儲存在用戶的瀏覽器中。

  2. 服務端快取(Server Cache):資源儲存在伺服器或中間層(如 CDN)。

  3. 應用層快取(Application Cache):由前端程式碼控制,例如使用 Service Worker 快取。

以下我會詳細說明瀏覽器快取的運作,並介紹如何用 JavaScript 實現簡單的快取控制。


瀏覽器快取的運作原理

瀏覽器快取是前端工程師最常接觸的快取機制,它由 HTTP 協議的標頭(Headers)控制。以下是快取的運作流程:

  1. 首次請求

    • 當用戶第一次訪問網頁時,瀏覽器向伺服器發送 HTTP 請求,取得資源(如 HTML、圖片等)。

    • 伺服器回應時,會在 HTTP 回應標頭中包含快取相關的指令(如 Cache-Control、ETag 等)。

    • 瀏覽器根據這些指令,將資源儲存到本地的快取記憶體(記憶體快取)或硬碟(磁碟快取)。

  2. 後續請求

    • 當用戶再次訪問相同資源時,瀏覽器會檢查快取中是否已有該資源。

    • 如果快取有效(根據標頭設定的規則),瀏覽器直接從快取載入資源,無需向伺服器發送請求。

    • 如果快取過期或無效,瀏覽器會向伺服器發送請求,確認資源是否更新。

  3. 快取驗證

    • 瀏覽器可能會發送條件式請求(如帶有 If-None-Match 或 If-Modified-Since 的請求),檢查資源是否改變。

    • 如果伺服器回應 304 Not Modified,表示資源未更新,瀏覽器繼續使用快取。

    • 如果資源已更新,伺服器會回傳新的資源和更新後的快取指令。

image.png


關鍵 HTTP 快取標頭

以下是控制瀏覽器快取的常見 HTTP 標頭,這些標頭通常由後端設定,但前端工程師需要了解其作用:

  1. Cache-Control

    • 控制快取行為的關鍵標頭。常見值包括:

      • max-age=<秒數>:快取有效時間(以秒為單位)。

      • no-cache:每次使用前需向伺服器驗證。

      • no-store:完全不快取。

      • public:允許任何快取儲存(包括 CDN)。

      • private:僅允許瀏覽器快取。

    • 範例:Cache-Control: max-age=3600 表示資源快取 1 小時。

  2. ETag

    • 伺服器為資源生成的唯一標識,用於驗證資源是否改變。

    • 範例:ETag: "abc123",瀏覽器會在後續請求中帶上 If-None-Match: "abc123"。

  3. Last-ModifiedIf-Modified-Since

    • Last-Modified 表示資源最後修改的時間。

    • 瀏覽器會在後續請求中帶上 If-Modified-Since,詢問伺服器資源是否更新。

  4. Expires

    • 指定快取的絕對過期時間(如 Expires: Wed, 13 Aug 2025 07:52:00 GMT)。

    • 現在較少使用,因為 Cache-Control: max-age 更靈活。


程式碼範例:使用 Service Worker 實現前端快取

Service Worker 是一種前端技術,允許開發者控制資源的快取,特別適合打造離線網頁或加速資源載入。以下是一個簡單的 Service Worker 範例,展示如何快取靜態資源。

步驟 1:建立 Service Worker 檔案

創建一個名為 sw.js 的檔案,放在你的專案根目錄:

// sw.js
// 定義快取名稱和要快取的資源
const CACHE_NAME = "my-site-cache-v1";
const urlsToCache = [
"/",
"/index.html",
"/styles.css",
"/script.js",
"/image.jpg",
];

// 安裝 Service Worker 並快取資源
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log("開啟快取");
return cache.addAll(urlsToCache);
})
);
});

// 攔截網路請求並從快取提供資源
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// 如果快取中有匹配的資源,直接回傳
if (response) {
return response;
}
// 否則發送網路請求
return fetch(event.request);
})
);
});

// 更新 Service Worker 並清理舊快取
self.addEventListener("activate", (event) => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});

步驟 2:在主程式中註冊 Service Worker

在你的 index.html 或主 JavaScript 檔案中註冊 Service Worker:

// script.js
// 檢查瀏覽器是否支援 Service Worker
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/sw.js")
.then((registration) => {
console.log("Service Worker 註冊成功:", registration);
})
.catch((error) => {
console.error("Service Worker 註冊失敗:", error);
});
});
}

步驟 3:將 Service Worker 加入 HTML

確保你的 index.html 載入主程式檔案:

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<title>網頁快取範例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>這是快取範例頁面</h1>
<img src="image.jpg" alt="範例圖片">
<script src="script.js"></script>
</body>
</html>

運作說明

  1. 安裝階段:當 Service Worker 註冊並啟動時,install 事件會觸發,將指定的資源(如 index.html、styles.css)儲存到快取中。

  2. 請求攔截:當瀏覽器發出請求時,fetch 事件會檢查快取中是否有匹配的資源。如果有,直接從快取回傳;否則,向伺服器請求。

  3. 更新快取:當 Service Worker 更新時,activate 事件會清理舊的快取,確保只保留最新的快取版本。


如何測試快取

  1. 開啟瀏覽器開發者工具

    • 在 Chrome 中,按 F12 開啟開發者工具,切換到「Application」標籤。

    • 查看「Cache Storage」或「Service Workers」,確認快取內容和 Service Worker 狀態。

  2. 模擬離線環境

    • 在「Network」標籤中,將「Online」改為「Offline」,重新整理頁面,確認是否從快取載入資源。
  3. 檢查 HTTP 標頭

    • 在「Network」標籤中,點選某個資源,檢查其回應標頭(如 Cache-Control、ETag)。

常見問題與解決方法

  1. 快取未生效

    • 檢查 Cache-Control 標頭是否正確設定。

    • 確認 Service Worker 是否正確註冊(檢查是否有錯誤訊息)。

  2. 資源未更新

    • 如果快取時間過長(max-age 過大),可縮短快取時間或使用 no-cache。

    • 在 Service Worker 中更新 CACHE_NAME,強制清除舊快取。

  3. Service Worker 未啟動

    • 確保網頁使用 HTTPS(本地開發可用 localhost)。

    • 檢查 sw.js 路徑是否正確。


總結

網頁快取機制透過瀏覽器快取和 Service Worker 等技術,能顯著提升網頁載入速度和離線體驗。作為前端工程師,你可以:

  1. 理解 HTTP 快取標頭(如 Cache-Control、ETag),與後端合作優化快取策略。

  2. 使用 Service Worker 實現自訂快取邏輯,特別適合單頁應用(SPA)或離線網頁。

  3. 透過瀏覽器開發者工具測試和除錯快取行為。