【高】HTTP 緩存策略你真的有了解嗎?

成都程序員晴小篆 發佈 2024-04-28T17:10:04.178925+00:00

HTTP緩存策略是指瀏覽器和伺服器之間在傳輸資源時,如何使用緩存的方式。HTTP緩存的主要目的是減少網絡傳輸的數據量,提高頁面的訪問速度。緩存的主要策略有哪些?

HTTP緩存策略是指瀏覽器和伺服器之間在傳輸資源時,如何使用緩存的方式。HTTP緩存的主要目的是減少網絡傳輸的數據量,提高頁面的訪問速度。

緩存的主要策略有哪些?

HTTP緩存策略主要包括以下幾種:

  • 強緩存:通過設置 HTTP 頭部中的 Expires 或 Cache-Control 欄位來指定資源在本地緩存的有效期。當資源未過期時,瀏覽器直接從緩存中讀取,不會向伺服器發送請求,從而提高頁面的訪問速度。
  • 協商緩存:當資源的緩存時間已經過期,瀏覽器會向伺服器發送請求,伺服器會檢查資源是否有更新,如果沒有更新,則返回 304 狀態碼,告訴瀏覽器直接使用本地緩存。
    • Last-Modified / If-Modified-Since:伺服器在返回資源時,會添加 Last-Modified 頭部欄位,表示資源最後的修改時間。當瀏覽器下次請求該資源時,會在請求頭部添加 If-Modified-Since 欄位,表示上次請求時資源的修改時間。伺服器檢查這兩個時間是否一致,如果一致,則返回 304 狀態碼,否則返回新的資源。
    • ETag / If-None-Match:伺服器在返回資源時,會添加 ETag 頭部欄位,表示資源的唯一標識。當瀏覽器下次請求該資源時,會在請求頭部添加 If-None-Match 欄位,表示上次請求時資源的唯一標識。伺服器檢查這兩個標識是否一致,如果一致,則返回 304 狀態碼,否則返回新的資源。
  • 離線緩存:通過使用 HTML5 提供的 Application Cache API,可以將頁面的資源緩存在本地,使得用戶在沒有網絡連接的情況下也能夠訪問頁面。
  • Service Worker 緩存:Service Worker 是一種在瀏覽器後台運行的 JavaScript 線程,可以攔截和處理瀏覽器發送的網絡請求。通過使用 Service Worker,可以將頁面的資源緩存在本地,提高頁面的訪問速度和用戶體驗。

強緩存中 Expires 或 Cache-Control 有什麼區別?

在 HTTP 緩存策略中,強緩存是指在一定時間內,直接使用本地緩存而不發送請求到伺服器。Expires 和 Cache-Control 是用於設置強緩存的兩種方式。

  • Expires: 是 HTTP/1 的產物,它是一個 HTTP 頭欄位,表示資源過期時間,是一個絕對時間。伺服器返回的 HTTP 頭中,如果包含 Expires 欄位,則表示該資源在該過期時間之前可以直接從緩存中獲取,而不需要再次請求伺服器。
  • Cache-Control: 是 HTTP/1.1 的產物,是一個 HTTP 頭欄位,用來控制文檔緩存行為。它的值可以是很多不同的指令,例如 max-age、no-cache、no-store、must-revalidate 等等。其中,max-age 指令可以設置資源的最大有效時間,單位是秒。如果伺服器返回的 HTTP 頭中包含 Cache-Control 指令,則瀏覽器會根據該指令的值來決定是否直接使用本地緩存,而不需要再次請求伺服器。

Expires 是一個絕對時間,因此它的缺點是當伺服器的時間與客戶端的時間不一致時,緩存過期時間就可能會出現偏差。
而 Cache-Control 是一個相對時間,因此它的缺點是需要伺服器和客戶端的時間保持一致,同時需要正確設置 max-age 的值。
在實際應用中,建議使用 Cache-Control,因為它更加靈活和可控。

離線緩存 Application Cache API 是如何緩存 http 資源的?

Application Cache API(應用程式緩存)是 HTML5 標準中提供的一個用於離線緩存 Web 應用程式的技術。它可以將 Web 應用程式中的文件(包括 HTML、CSS、Javascript 和圖像等)保存到客戶端瀏覽器中的緩存中,在沒有網絡連接的情況下,仍然能夠訪問應用程式。

在 Application Cache API 中,通過在 cache manifest 文件中列出需要緩存的資源列表來實現離線緩存。該文件必須以 .appcache 為後綴名,並且必須在 Web 伺服器上進行訪問。瀏覽器會下載該文件,並將文件中列出的資源文件下載到本地緩存中。當應用程式在離線狀態下打開時,瀏覽器會自動從本地緩存中加載緩存的文件。

下面是一個簡單的 cache manifest 文件示例:

CACHE MANIFEST
# version 1.0.0

CACHE:
index.html
styles.css
script.js
image.jpg

NETWORK:
*

FALLBACK:

上面的示例文件將緩存 index.html、styles.css、script.js 和 image.jpg 等資源文件,同時指定 NETWORK 和 FALLBACK,這兩個屬性分別用於指定離線緩存不生效時的網絡連接策略和替換資源文件。

需要注意的是,Application Cache API 並不是一種完美的緩存技術,它也存在一些缺陷。例如,當更新 Web 應用程式時,需要手動清除客戶端瀏覽器中的緩存才能生效,否則用戶訪問的仍然是舊版本的應用程式。同時,Application Cache API 只能緩存 GET 請求,不支持 POST 等其他請求方法。因此,為了更好地實現離線緩存,可以使用其他技術,例如 Service Worker。

Service Worker 是如何緩存 http 請求資源的?

ervice Worker 是一種在瀏覽器後台運行的腳本,可以攔截和處理瀏覽器網絡請求。因此,可以使用 Service Worker 來緩存 http 請求資源。

Service Worker 可以通過以下步驟來緩存 http 請求資源:

  1. 註冊 Service Worker:通過在頁面中註冊 Service Worker,可以告訴瀏覽器使用 Service Worker 來處理網絡請求。
  2. 安裝 Service Worker:一旦 Service Worker 被註冊,瀏覽器就會下載並安裝它。在安裝過程中,Service Worker 可以緩存一些靜態資源(如 HTML、CSS 和 JavaScript 文件)。
  3. 激活 Service Worker:一旦 Service Worker 安裝成功,它就可以被激活。在激活過程中,Service Worker 可以刪除舊版本的緩存,或者執行其他一些操作。
  4. 攔截網絡請求:一旦 Service Worker 被激活,它就可以攔截瀏覽器發送的網絡請求。
  5. 處理網絡請求:當 Service Worker 攔截到網絡請求時,它可以執行一些自定義的邏輯來處理這些請求。例如,它可以檢查緩存中是否已經存在該請求的響應,如果存在,則直接返回緩存中的響應,否則,它可以將請求發送到伺服器並緩存伺服器的響應。
  6. 更新緩存:如果緩存中的資源發生了變化,Service Worker 可以自動更新緩存。例如,它可以在後台下載最新的資源,並更新緩存中的文件。

需要注意的是,使用 Service Worker 來緩存 http 請求資源需要一些額外的工作。例如,需要編寫 Service Worker 腳本來處理請求,並且需要將該腳本註冊到瀏覽器中。此外,還需要考慮一些緩存策略,以確保緩存的數據與伺服器上的數據保持同步。

下面是一個使用 Service Worker 實現緩存的示例代碼:

// 註冊 Service Worker
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
      console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }, function(err) {
      console.log('ServiceWorker registration failed: ', err);
    });
  });
}

// 安裝 Service Worker
self.addEventListener('install', function(event) {
  console.log('ServiceWorker install');
  event.waitUntil(
    caches.open('my-cache').then(function(cache) {
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/script.js',
        '/image.png'
      ]);
    })
  );
});

// 激活 Service Worker
self.addEventListener('activate', function(event) {
  console.log('ServiceWorker activate');
});

// 攔截網絡請求
self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      if (response) {
        console.log('ServiceWorker fetch from cache:', event.request.url);
        return response;
      } else {
        console.log('ServiceWorker fetch from network:', event.request.url);
        return fetch(event.request);
      }
    })
  );
});

// 更新緩存
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(cacheName => {
          return cacheName.startsWith('my-cache') &&
            cacheName !== 'my-cache';
        }).map(cacheName => {
          return caches.delete(cacheName);
        })
      );
    })
  );
});

當網絡請求到來時,會首先在緩存中查找對應的資源,如果有則直接返回緩存中的資源,否則從網絡中獲取資源並返回。這樣就可以實現基本的離線緩存功能。

在這個示例中,當 Service Worker 被安裝時,我們打開一個新的緩存並將應用程式的靜態資源添加到緩存中。在 fetch 事件中,我們攔截每個網絡請求並嘗試匹配它們到我們的緩存中,如果匹配到了則返回緩存的響應,否則通過 fetch 方法從網絡中獲取資源。在 activate 事件中,我們可以更新緩存,刪除舊的緩存項並將新的緩存項添加到緩存中。

關鍵字: