網頁的快取機制是怎麼運作的?
什麼是網頁快取?
網頁快取(Caching)是指瀏覽器或伺服器將網頁資源(如 HTML 文件、圖片、CSS、JavaScript 檔案等)儲存在本地或中間層,以減少重複請求、加快載入速度並降低伺服器負擔的技術。快取機制可以讓用戶在重複訪問網頁時,快速取得資源,而不需要每次都從伺服器下載。
快取主要分為以下幾種類型:
-
瀏覽器快取(Browser Cache):資源儲存在用戶的瀏覽器中。
-
服務端快取(Server Cache):資源儲存在伺服器或中間層(如 CDN)。
-
應用層快取(Application Cache):由前端程式碼控制,例如使用 Service Worker 快取。
以下我會詳細說明瀏覽器快取的運作,並介紹如何用 JavaScript 實現簡單的快取控制。
瀏覽器快取的運作原理
瀏覽器快取是前端工程師最常接觸的快取機制,它由 HTTP 協議的標頭(Headers)控制。以下是快取的運作流程:
-
首次請求:
-
當用戶第一次訪問網頁時,瀏覽器向伺服器發送 HTTP 請求,取得資源(如 HTML、圖片等)。
-
伺服器回應時,會在 HTTP 回應標頭中包含快取相關的指令(如 Cache-Control、ETag 等)。
-
瀏覽器根據這些指令,將資源儲存到本地的快取記憶體(記憶體快取)或硬碟(磁碟快取)。
-
-
後續請求:
-
當用戶再次訪問相同資源時,瀏覽器會檢查快取中是否已有該資源。
-
如果快取有效(根據標頭設定的規則),瀏覽器直接從快取載入資源,無需向伺服器發送請求。
-
如果快取過期或無效,瀏覽器會向伺服器發送請求,確認資源是否更新。
-
-
快取驗證:
-
瀏覽器可能會發送條件式請求(如帶有 If-None-Match 或 If-Modified-Since 的請求),檢查資源是否改變。
-
如果伺服器回應 304 Not Modified,表示資源未更新,瀏覽器繼續使用快取。
-
如果資源已更新,伺服器會回傳新的資源和更新後的快取指令。
-
關鍵 HTTP 快取標頭
以下是控制瀏覽器快取的常見 HTTP 標頭,這些標頭通常由後端設定,但前端工程師需要了解其作用:
-
Cache-Control:
-
控制快取行為的關鍵標頭。常見值包括:
-
max-age=
<秒數>
:快取有效時間(以秒為單位)。 -
no-cache:每次使用前需向伺服器驗證。
-
no-store:完全不快取。
-
public:允許任何快取儲存(包括 CDN)。
-
private:僅允許瀏覽器快取。
-
-
範例:Cache-Control: max-age=3600 表示資源快取 1 小時。
-
-
ETag:
-
伺服器為資源生成的唯一標識,用於驗證資源是否改變。
-
範例:ETag: "abc123",瀏覽器會在後續請求中帶上 If-None-Match: "abc123"。
-
-
Last-Modified 和 If-Modified-Since:
-
Last-Modified 表示資源最後修改的時間。
-
瀏覽器會在後續請求中帶上 If-Modified-Since,詢問伺服器資源是否更新。
-
-
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>
運作說明
-
安裝階段:當 Service Worker 註冊並啟動時,install 事件會觸發,將指定的資源(如 index.html、styles.css)儲存到快取中。
-
請求攔截:當瀏覽器發出請求時,fetch 事件會檢查快取中是否有匹配的資源。如果有,直接從快取回傳;否則,向伺服器請求。
-
更新快取:當 Service Worker 更新時,activate 事件會清理舊的快取,確保只保留最新的快取版本。
如何測試快取
-
開啟瀏覽器開發者工具:
-
在 Chrome 中,按 F12 開啟開發者工具,切換到「Application」標籤。
-
查看「Cache Storage」或「Service Workers」,確認快取內容和 Service Worker 狀態。
-
-
模擬離線環境:
- 在「Network」標籤中,將「Online」改為「Offline」,重新整理頁面,確認是否從快取載入資源。
-
檢查 HTTP 標頭:
- 在「Network」標籤中,點選某個資源,檢查其回應標頭(如 Cache-Control、ETag)。
常見問題與解決方法
-
快取未生效:
-
檢查 Cache-Control 標頭是否正確設定。
-
確認 Service Worker 是否正確註冊(檢查是否有錯誤訊息)。
-
-
資源未更新:
-
如果快取時間過長(max-age 過大),可縮短快取時間或使用 no-cache。
-
在 Service Worker 中更新 CACHE_NAME,強制清除舊快取。
-
-
Service Worker 未啟動:
-
確保網頁使用 HTTPS(本地開發可用 localhost)。
-
檢查 sw.js 路徑是否正確。
-
總結
網頁快取機制透過瀏覽器快取和 Service Worker 等技術,能顯著提升網頁載入速度和離線體驗。作為前端工程師,你可以:
-
理解 HTTP 快取標頭(如 Cache-Control、ETag),與後端合作優化快取策略。
-
使用 Service Worker 實現自訂快取邏輯,特別適合單頁應用(SPA)或離線網頁。
-
透過瀏覽器開發者工具測試和除錯快取行為。