透過網路擷取資源不但速度慢,成本也很高:
- 大型回應需要瀏覽器與伺服器之間進行多次往返作業。
- 網頁的所有重要資源下載完畢後,才會載入。
- 如果使用者以有限的行動數據方案存取您的網站,每一個不必要的網路要求都會浪費他們的金錢。
如何避免不必要的網路要求?瀏覽器的 HTTP 快取是您的第一道防線。這不一定是最強大或最有彈性的方法,而且您對快取回應的生命週期有限,但這個方法有效,而且適用於所有瀏覽器,而且不需要進行大量操作。
本指南說明有效 HTTP 快取實作的基本概念。
瀏覽器相容性
實際上並沒有一個稱為 HTTP 快取的 API,這是一系列網路平台 API 的全名。所有瀏覽器都支援下列 API:
Cache-Control
ETag
Last-Modified
HTTP 快取的運作方式
瀏覽器提出的所有 HTTP 要求會先轉送至瀏覽器快取,檢查是否具備可用於執行要求的有效快取回應。如果比對結果相符,系統就會從快取中讀取回應,進而消除網路延遲時間和移轉作業產生的資料費用。
HTTP 快取的行為是由要求標頭和回應標頭的組合控管。在理想的情況下,您可以控制網頁應用程式的程式碼 (決定要求標頭) 和網路伺服器的設定 (會決定回應標頭)。
如要深入瞭解概念總覽,請參閱 MDN 的 HTTP 快取文章。
要求標頭:沿用預設值 (通常)
網頁應用程式的傳出要求中,應包含幾個重要標頭,但瀏覽器在發出要求時,幾乎一律會代您設定這些標頭。會影響檢查更新間隔的要求標頭 (例如 If-None-Match
和 If-Modified-Since
),系統會根據瀏覽器目前解讀 HTTP 快取的值。
好消息!您可以繼續在 HTML 中加入 <img src="my-image.png">
之類的標記,瀏覽器會自動為您處理 HTTP 快取,
回應標頭:設定網路伺服器
HTTP 快取設定最重要的部分是網路伺服器新增至每個傳出回應的標頭。下列標頭全都影響到有效的快取行為:
Cache-Control
。伺服器可以傳回Cache-Control
指令,指定瀏覽器和其他中繼快取應快取個別回應的方式和時間長度。ETag
。當瀏覽器找到過期的快取回應時,會傳送一個小型憑證 (通常是檔案內容的雜湊) 給伺服器,檢查檔案是否有所變更。如果伺服器傳回相同的權杖,檔案就會是相同的,不需要重新下載。Last-Modified
。這個標頭的用途與ETag
相同,但會使用以時間為準的策略來判斷資源是否已變更,而非採用以內容為基礎的策略ETag
。
有些網路伺服器內建支援,可預設設定這些標頭,有些則會完全省略標頭,除非您明確設定標頭。設定標頭的具體細節會因您使用的網路伺服器而異,因此請參閱伺服器的說明文件,取得最準確的詳細資料。
為了節省搜尋時間,請按照以下指示設定幾個熱門的網路伺服器:
離開 Cache-Control
回應標頭並不會停用 HTTP 快取!相反地,瀏覽器可以有效推測哪種快取行為最適合特定類型的內容。您可能想要擁有比方案更多的掌控權,因此請花點時間設定回應標頭。
你應該使用哪些回應標頭值?
設定廣告活動時,應涵蓋兩個重要情境 網路伺服器的回應標頭
用於版本化網址的長期快取
假設您的伺服器指示瀏覽器快取 CSS 檔案一年 (Cache-Control: max-age=31536000
),但設計人員剛進行了必須立即部署的緊急更新,如何通知瀏覽器更新「過時」檔案的快取副本?如要這麼做,至少必須先變更資源網址。
瀏覽器快取回應後,將使用快取版本,直到 max-age
或 expires
已無更新,或因其他原因 (例如使用者清除瀏覽器快取) 從快取中移除為止。因此,建構網頁時,不同的使用者可能會使用不同的檔案版本:剛擷取資源的使用者改用新版本,而較早 (但仍有效) 副本的使用者則使用舊版本的回應。
如何發揮用戶端快取和快速更新的優勢?然後,您變更資源網址,並強制使用者在內容變更時下載新的回應。通常只要在檔案名稱中嵌入檔案指紋或版本號碼即可,例如 style.x234dff.css
。
回應包含「指紋」的網址要求時或版本資訊,以及內容不會變動的內容,請在回應中加入 Cache-Control: max-age=31536000
。
設定這個值可讓瀏覽器在明年 (31,536,000 秒;支援的值上限) 於未來一年內隨時載入相同的網址時,它可以立即使用 HTTP 快取中的值,而完全不需向網路伺服器發出網路要求。太棒了—您立即成功瞭解避開網路而造成的可靠性和速度!
webpack 等建構工具可自動處理為素材資源網址指派雜湊指紋的程序。
伺服器對未版本化網址進行重新驗證
很抱歉,您載入的部分網址並未建立版本。也許您無法在部署網頁應用程式前納入建構步驟,因此無法在素材資源網址中加入雜湊。此外,每個網頁應用程式都需要 HTML 檔案,這些檔案幾乎不會包含版本資訊,因為如果使用者需要記得要造訪的網址是 https://example.com/index.34def12.html
,他們就無法使用您的網頁應用程式。那麼 Google 對這些網址有什麼幫助?
也就是您必須承受擊敗的那種情境。單靠 HTTP 快取功能不夠強大,無法完全避開網路。(請放心,您很快就會瞭解服務工作人員,這些工作人員會提供所需支援,幫助我們放鬆,對您有利)。不過,您可以採取幾個步驟,確保網路要求的速度和效率都有所提升。
下列 Cache-Control
值可協助您微調快取網址的快取位置和方式:
no-cache
。這會指示瀏覽器每次使用網址的快取版本前,都必須向伺服器重新驗證。no-store
。這會指示瀏覽器和其他中繼快取 (例如 CDN) 一律不儲存任何檔案版本。private
。瀏覽器可以快取檔案,但中繼快取無法快取。public
。回應可由任何快取儲存。
請參閱附錄:Cache-Control
流程圖,以視覺化的方式呈現決定使用哪個 Cache-Control
值的程序。Cache-Control
也能接受以半形逗號分隔的指令清單。請參閱附錄:Cache-Control
範例。
設定 ETag
或 Last-Modified
也有幫助。如回應標頭中所述,ETag
和 Last-Modified
都具有相同的用途,也就是判斷瀏覽器是否需要重新下載已過期的快取檔案。建議您使用 ETag
,因為這個方法更為準確。
假設從初次擷取至今已經過 120 秒,且瀏覽器對相同的資源發出新的要求。首先,瀏覽器會檢查 HTTP 快取,並找出先前的回應。很抱歉,瀏覽器無法使用先前的回應,因為回應已過期。此時,瀏覽器可分派新的要求,並擷取新的完整回應。然而,這種做法效率較低,因為資源並未變更,就沒有理由下載快取中的相同資訊!
這就是 ETag
標頭中指定的驗證權杖的問題。伺服器會產生並傳回任意權杖,此權杖通常是檔案內容的雜湊或其他指紋。瀏覽器不需要知道指紋的產生方式。只要在下一個要求中將該要求傳送至伺服器即可。如果指紋維持不變,表示資源並未變更,瀏覽器會略過下載作業。
設定 ETag
或 Last-Modified
可讓要求觸發要求標頭中提及的 If-Modified-Since
或 If-None-Match
要求標頭,讓重新驗證要求更有效率。
設定妥當的網路伺服器查看收到要求標頭時,即可確認瀏覽器在 HTTP 快取中已有的資源版本,與網路伺服器上的最新版本相符。如果相符,伺服器可以傳回 304 Not Modified
HTTP 回應,相當於「嘿,繼續使用現有的內容!」傳送這類回應時,傳輸的資料量很少,因此比起實際傳回要求的實際資源副本,通常更快得多。
摘要
HTTP 快取可減少不必要的網路要求,因此能有效改善載入效能。受到所有瀏覽器支援,而且不需太多工作就能完成設定。
建議您從以下 Cache-Control
設定著手:
Cache-Control: no-cache
表示應在每次使用前,透過伺服器重新驗證的資源。Cache-Control: no-store
代表不應快取的資源。Cache-Control: max-age=31536000
代表版本化資源。
而 ETag
或 Last-Modified
標頭則可協助您更有效率地重新驗證過期的快取資源。
瞭解詳情
如果想要使用 Cache-Control
標頭以外的基礎知識,請參閱 Jake Archibald 的「快取最佳做法和 max-age 作業」指南。
請參閱「快取快取」,瞭解如何針對回訪者最佳化快取使用方式。
附錄:更多訣竅
如果你有更多時間,可以透過下列方法最佳化 HTTP 快取:
- 使用一致的網址。如果您在不同網址提供相同的內容,系統會多次擷取及儲存該內容。
- 將流失率降到最低。如果資源的一部分 (例如 CSS 檔案) 經常更新,但檔案的其餘部分不會 (例如程式庫程式碼),請考慮將經常更新的程式碼分割成單獨的檔案,並針對經常更新的程式碼,以及針對不常變更的程式碼,使用長時間的快取持續時間策略。
- 如果您的
Cache-Control
政策可接受某種程度的過時程度,請檢查新的stale-while-revalidate
指令。
附錄:Cache-Control
流程圖
附錄:Cache-Control
個範例
Cache-Control 值 |
說明 |
---|---|
max-age=86400 |
瀏覽器和中介快取可快取回應內容,時間最長可達 1 天 (60 秒 x 60 分鐘 x 24 小時)。 |
private, max-age=600 |
瀏覽器可以快取回應 (而非中介快取),最長可達 10 分鐘 (60 秒 x 10 分鐘)。 |
public, max-age=31536000 |
回應內容可由任何快取儲存 1 年。 |
no-store |
系統不允許快取回應,且每次要求都必須完整擷取。 |