透過網路擷取資源既緩慢,又所費不貲:
- 大型回應需要在瀏覽器和伺服器之間來回往返。
- 網頁必須先完全下載所有重要資源,系統才會載入網頁。
- 如果使用者是透過有限的行動數據方案存取您的網站,所有不必要的網路要求都會浪費金錢。
如何避免不必要的網路要求?瀏覽器的 HTTP 快取是第一道防線這不是最強大或最靈活的方法,您對於快取回應的生命週期擁有有限的掌控權,但這項功能也有效,所有瀏覽器都支援,而且不需要做太多工作。
本指南說明有效 HTTP 快取實作的基本概念。
瀏覽器相容性
實際上並沒有呼叫 HTTP 快取的單一 API。這是一組網路平台 API 的一般名稱所有瀏覽器都支援這些 API:
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 檔案 1 年 (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
那你可以對這些網址進行什麼操作?
你必須承認敗場。光是 HTTP 快取功能不夠強大,無法完全避開網路。(別擔心,您不久後就會學到「Service Worker」,這將提供我們需要的支援,讓您將戰鬥擺脫並贏得您支持。)不過,您仍可採取幾個步驟,確保網路要求盡可能快速且有效率。
下列 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 回應,相當於「Ok,繼續使用目前擁有的內容!」傳送這類回應時,因為僅需要轉移少量資料,因此通常比必須實際回傳實際資源副本要來得快。
摘要
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 檔案) 會經常更新,而檔案的其餘部分 (例如程式庫程式碼) 不會更新,請考慮將經常更新的程式碼分割成個別檔案,並針對經常更新的程式碼使用短的時間快取策略,並針對不會經常變更的程式碼採用較長的快取時間策略。
- 檢查新的
stale-while-revalidate
指令,如果您的Cache-Control
政策允許某種程度的過時程度資料。
附錄: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 |
系統不允許快取回應,且每次要求時都必須完整擷取回應。 |