使用 HTTP 快取,避免不必要的網路要求

Ilya Grigorik
Ilya Grigorik

透過網路擷取資源既緩慢,又所費不貲:

  • 大型回應需要在瀏覽器和伺服器之間來回多次轉換。
  • 網頁要等到所有重要資源下載完成才會載入。
  • 如果您網站上的使用者採用有限的行動數據方案,則每個不必要的網路要求都會浪費資金。

如何避免不必要的網路要求?瀏覽器的 HTTP 快取是第一道防線這不是最強大或最靈活的方法,您對於快取回應的生命週期擁有有限的掌控權,但這項功能也有效,所有瀏覽器都支援,而且不需要做太多工作。

本指南說明有效 HTTP 快取實作的基本概念。

瀏覽器相容性

HTTP 快取是所有瀏覽器支援的網路平台 API 集合的一般名稱:

Cache-Control

瀏覽器支援

  • 12

來源

ETag

瀏覽器支援

  • 12

來源

Last-Modified

瀏覽器支援

  • 12

來源

HTTP 快取的運作方式

瀏覽器提出的所有 HTTP 要求會先轉送至瀏覽器快取,確認是否有可用於執行要求的有效快取回應。如果比對相符,就會從快取中讀取回應,避免網路延遲和傳輸的數據用量。

HTTP 快取的行為是由要求標頭回應標頭的組合控制。在理想情況下,您可以控制網頁應用程式的程式碼,進而決定要求標頭,以及決定回應標頭的網路伺服器設定。

如需更深入的概念總覽,請參閱 MDN 的 HTTP 快取一文。

要求標頭:保留預設值 (通常)

有些重要標頭應納入網頁應用程式的傳出要求,但瀏覽器在發出要求時,幾乎一律會替您設定這些標頭。系統會根據瀏覽器對於 HTTP 快取中目前值的瞭解,顯示會影響檢查更新頻率的要求標頭 (例如 If-None-MatchIf-Modified-Since)。

好消息是,這表示您可以繼續在 HTML 中加入 <img src="my-image.png"> 等標記,瀏覽器會自動代您處理 HTTP 快取作業,您不必額外做任何工作。

回應標頭:設定網路伺服器

HTTP 快取設定中最重要的部分,是網路伺服器會在每個傳出回應中新增的標頭。下列標頭都會影響有效的快取行為:

Cache-Control
伺服器可以傳回 Cache-Control 指令,藉此指定瀏覽器和其他中繼快取應快取個別回應的方式和時間長度。
ETag.
瀏覽器找到過期的快取回應時,可將小型權杖 (通常是檔案內容的雜湊) 傳送至伺服器,檢查檔案是否已變更。如果伺服器傳回相同的權杖,檔案就是相同的,無需重新下載。
Last-Modified
此標頭的用途與 ETag 相同,但會使用以時間為準的策略,判斷資源是否已變更,而非 ETag 的內容式策略。

部分網路伺服器預設會支援設定這些標頭。有些則除非您明確設定標頭,否則標頭會完全排除。「如何」設定標頭的具體細節因您使用的網路伺服器而異,如需最準確的詳細資料,請參閱伺服器的說明文件。

為節省您的搜尋時間,以下是一些常用網路伺服器的設定操作說明:

省略 Cache-Control 回應標頭並不會停用 HTTP 快取! 反而能夠有效猜測哪種類型的快取行為對特定類型的內容最有意義。您或許會想進一步控制優惠內容,因此必須花一些時間設定回應標頭。

您應該使用哪種回應標頭值?

設定網路伺服器的回應標頭時,應考量以下兩個重要情境。

版本化網址的長效快取

版本化網址對快取策略有何助益
建議您管理版本化網址,因為這樣較容易使快取回應失效。

假設您的伺服器指示瀏覽器快取 CSS 檔案 1 年 (Cache-Control: max-age=31536000),但設計人員剛進行緊急更新,而您必須立即導入此更新。如何通知瀏覽器更新檔案的「過時」快取副本? 您不能變更資源網址。

瀏覽器快取回應後,系統就會使用快取版本,直到不再更新 (由 max-ageexpires 決定),或基於其他原因 (例如使用者清除瀏覽器快取) 從快取中移除。因此,建構網頁時,不同的使用者最後可能會載入不同版本的檔案:剛擷取資源的使用者會使用新版本,但先前快取 (但仍有效) 副本的使用者卻使用的是舊版本。

如要同時取得用戶端快取和快速更新,您可以變更資源網址,並強制使用者在每次內容變更時下載新回應。一般而言,您可以在檔案名稱中嵌入檔案指紋或版本號碼,例如:style.x234dff.css

如要回應含有「指紋」或版本資訊,且其內容永遠不會改變的要求,請在回應中加入 Cache-Control: max-age=31536000

設定這個值會告知瀏覽器,如果明年隨時需要載入同一個網址 (31,536,000 秒,支援最大值),可以直接使用 HTTP 快取中的值,而無需向網路伺服器發出網路要求。也就是說,您可以立即獲得避開網路所帶來的可靠性和速度!

Webpack 等建構工具可自動執行指派雜湊指紋給資產網址的程序

針對未版本網址重新驗證伺服器

不過,並非所有載入的網址都已建立版本。也許您無法在部署網頁應用程式之前納入建構步驟,因此無法將雜湊新增至資產網址。而且每個網頁應用程式都需要 HTML 檔案,因為這類檔案幾乎永遠不會包含版本管理資訊,因為如果沒有人需要記住要造訪的網址為 https://example.com/index.34def12.html,就不再需要使用網頁應用程式。那你可以對這些網址進行什麼操作?

本身 HTTP 快取功能不夠強大,無法完全避免網路問題。(請放心,您很快就會瞭解服務工作站,這會提供額外支援。)不過,您仍可採取幾個步驟,確保網路要求盡可能快速且有效率。

下列 Cache-Control 值可協助您微調快取未版本網址的位置和方式:

  • no-cache 會告知瀏覽器,使用網址的快取版本前,每次都必須向伺服器重新驗證。
  • no-store 會告知瀏覽器和其他中繼快取 (例如 CDN) 一律不儲存檔案版本。
  • private:瀏覽器可以快取檔案,但中繼快取無法快取。
  • public:任何快取都可以儲存回應。

請參閱「附錄:Cache-Control 流程圖」,以視覺化方式呈現決定要使用哪個 Cache-Control 值的程序。Cache-Control 也可以接受以半形逗號分隔的指令清單。請參閱附錄:Cache-Control 範例

設定 ETagLast-Modified 也有助於解決問題。 如回應標頭中所述,ETagLast-Modified 用途相同:判斷瀏覽器是否需要重新下載已過期的快取檔案。建議使用 ETag,因為這樣會更加準確。

ETag 範例

假設初始擷取時間已經過 120 秒,且瀏覽器對相同資源發出了新的要求。首先,瀏覽器會檢查 HTTP 快取,並找出先前的回應。很抱歉,瀏覽器無法再使用先前的回覆,因為回應已過期。這時瀏覽器就可以分派新的要求,並擷取新的完整回應。但效率不彰,因為如果資源沒有變更,就沒有理由重新下載快取中的現有資訊。
這正是 ETag 驗證權杖所設計的問題。伺服器會產生並傳回任意權杖,這類權杖通常是檔案內容的雜湊或其他指紋。瀏覽器不需要知道指紋的產生方式。只需要在下一個要求中將其傳送至伺服器即可。如果指紋仍然相同,則資源並未變更,且瀏覽器可以略過下載作業。

設定 ETagLast-Modified 可讓重新驗證要求觸發要求標頭中提及的 If-Modified-SinceIf-None-Match 要求標頭,更有效率。

如果正確設定的網路伺服器查看傳入要求標頭,即可確認瀏覽器在 HTTP 快取中已有的資源版本,是否與網路伺服器的最新版本相符。如果比對相符,伺服器可以傳回 304 Not Modified HTTP 回應,相當於「Ok,繼續使用目前擁有的內容!」傳送這類回應時,因為僅需要轉移少量資料,因此通常比必須實際回傳實際資源副本要來得快。

要求資源的用戶端和伺服器以 304 標頭回應的圖表。
瀏覽器向伺服器要求 /file,且包含 If-None-Match 標頭,指示伺服器只有在伺服器上檔案的 ETag 與瀏覽器的 If-None-Match 值不符時,才會傳回完整檔案。在這種情況下,這些值相符,因此伺服器會傳回 304 Not Modified 回應,說明應快取檔案的時間長度 (Cache-Control: max-age=120)。

摘要

HTTP 快取可減少不必要的網路要求,是改善載入效能的有效方式。這項功能適用於所有瀏覽器,且能快速設定完畢。

您可以參考下列 Cache-Control 設定:

  • Cache-Control: no-cache
  • Cache-Control: no-store 代表不應快取的資源。
  • Cache-Control: max-age=31536000 適用於版本化資源。

ETagLast-Modified 標頭可協助您更有效率地重新驗證過期的快取資源。

瞭解詳情

如果想要使用 Cache-Control 標頭的基本使用方法,請參閱 Jake Archibald 的快取最佳做法和 max-age 錯誤指南。

如要瞭解如何為回訪者最佳化快取用量,請參閱「快取遺失」一文。

附錄:其他提示

如有更多時間,以下進一步介紹最佳的 HTTP 快取使用方式:

  • 使用一致的網址。如果您在不同網址提供相同內容,瀏覽器會多次擷取並儲存該內容。
  • 盡可能降低流失率。如果資源的一部分 (例如 CSS 檔案) 會經常更新,而檔案的其餘部分不會 (如同程式庫程式碼) 更新,建議您將經常更新的程式碼分割至個別檔案,並針對經常更新的程式碼使用短時間快取策略,並針對不會經常變更的程式碼採用較長的快取時間長度策略。
  • 如果 Cache-Control 政策可接受某種程度的過時程度,請考慮新的 stale-while-revalidate 指令。

附錄:Cache-Control 流程圖

流程圖
設定 Cache-Control 標頭的決策程序。

附錄:Cache-Control 範例

Cache-Control 說明
max-age=86400 回應可由瀏覽器和中介快取快取長達一天 (60 秒 x 60 分鐘 x 24 小時)。
private, max-age=600 回應可由瀏覽器快取,但中介快取作業最多為十分鐘 (60 秒 x 10 分鐘)。
public, max-age=31536000 回應可由任何快取儲存一年。
no-store 無法快取回應,且每次要求時都必須完整擷取回應。