使用者第二次載入網站時會使用 HTTP 快取,因此請確保快取運作正常。
這篇文章是愛上快取影片的延伸內容,該影片是 2020 年 Chrome 開發人員大會的延伸內容。請務必觀看這部影片:
使用者第二次載入網站時,瀏覽器會使用 HTTP 快取中的資源,加快載入速度。不過,網路快取標準可追溯至 1999 年,而且定義相當廣泛,因此要判斷 CSS 或圖片等檔案是否可從網路重新擷取,而非從快取中載入,這項作業的準確度就會降低。
在本文中,我將介紹合理且新穎的快取預設值,實際上「完全不快取」。但這只是預設值,當然比「關閉」更細微。快繼續往下閱讀吧!
目標
網站第 2 次載入時,您有兩個目標:
- 確保使用者能取得最新版本,如果您有任何變更,應能快速反映
- 執行 #1,同時盡量減少從網路擷取的資料
從廣義來說,您只想在客戶重新載入網站時,將最小的變更傳送給客戶。而且,要將網站架構得宜,確保能以最有效率的方式發布任何變更,這項挑戰相當艱鉅 (詳情請見下文和影片)。
不過,考量快取時,您還有其他調整選項,例如決定讓使用者的瀏覽器 HTTP 快取長時間保留您的網站,這樣一來,就不需要任何網路要求就能提供網站。或者,您已建構 Service Worker,可在檢查網站是否為最新版本之前,提供完全離線的網站服務。這是極端的做法,但確實有效,而且可用於許多離線優先應用程式類型的網頁體驗。不過,網頁不必採用只使用快取的極端做法,甚至不必完全採用只使用網路的極端做法。
背景
身為網頁開發人員,我們都習慣「快取過期」的概念。但我們幾乎本能地知道,有哪些工具可用來解決這個問題:執行「強制重新整理」或開啟無痕式視窗,或是使用瀏覽器開發人員工具的組合,清除網站資料。
一般網際網路使用者就沒有這麼幸運。因此,雖然我們有幾項核心目標,確保使用者在第 2 次載入時能獲得良好體驗,但也非常重視確保使用者不會遇到不良體驗或卡住的情況。(如果想聽我談論我們如何差點讓 web.dev/live 網站卡住,請觀看影片)
稍微說明一下背景資訊,「陳舊快取」的常見原因其實是 1999 年快取的預設值。這項技術仰賴 Last-Modified
標頭:
您載入的每個檔案都會保留目前生命週期的 10%,以便瀏覽器查看。舉例來說,如果 index.html
是在一個月前建立,瀏覽器會將其快取約三天。
這在當時是個好意,但考量到現今網站的高度整合性,這個預設行為可能會導致使用者擁有為不同網站版本設計的檔案 (例如星期二版本的 JS 和星期五版本的 CSS),因為這些檔案並未在同一時間更新。
光線充足的路徑
現代快取的預設做法是完全不快取,並使用CDN 將內容提供給使用者。每當使用者載入您的網站時,都會前往網路查看網站是否為最新版本。這項要求會由地理位置上靠近每位使用者的 CDN 提供,因此延遲時間較短。
您可以設定網路主機,以便透過此標頭回應網路要求:
Cache-Control: max-age=0,must-revalidate,public
這基本上表示檔案的有效期限為零,您必須透過網路驗證檔案,才能再次使用 (否則只是「建議」)。
就傳輸位元組而言,這個驗證程序的成本相對較低,如果大型圖片檔案未變更,瀏覽器會收到小型 304 回應,但這會產生延遲,因為使用者仍必須前往網路才能查看。這也是這種做法的主要缺點。對於在第一世界國家中使用快速連線,且所選 CDN 涵蓋範圍廣泛的使用者來說,這項功能非常實用,但對於使用較慢行動連線或基礎架構不佳的使用者來說,就沒有太大幫助。
無論如何,這都是一種新式做法,也是熱門 CDN Netlify 的預設做法,但幾乎所有 CDN 都可以設定這項做法。針對 Firebase 代管服務,您可以在 firebase.json 檔案的代管區段中加入這個標頭:
"headers": [
// Be sure to put this last, to not override other headers
{
"source": "**",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=0,must-revalidate,public"
}
}
]
因此,雖然我仍建議採用這個做為合理的預設值,但這只是預設值!請繼續閱讀,瞭解如何介入並升級預設值。
指紋網址
在網站上提供的素材資源、圖片等名稱中加入檔案內容的雜湊,即可確保這些檔案一律含有獨特的內容,例如檔案名稱為 sitecode.af12de.js
。當伺服器回應這些檔案的要求時,您可以使用這個標頭設定瀏覽器,安全地指示終端使用者瀏覽器將這些檔案快取一段長時間:
Cache-Control: max-age=31536000,immutable
這個值以秒為單位。根據規格,這實際上等同於「永久」。
重要的是,請勿手動產生這些雜湊,因為這需要太多手動作業!您可以使用 Webpack、Rollup 等工具來處理這個問題。請務必參閱工具報告,進一步瞭解這些指標。
請注意,除了 JavaScript 之外,圖示、CSS 和其他不可變動的資料檔案等資產,也可以使用這種方式命名。(請務必觀看上述影片,進一步瞭解程式碼分割作業,這樣您在網站變更時,就能傳送更少的程式碼)。
無論您的網站如何快取,這類指紋檔案對您可能建立的任何網站都非常有用。大多數網站並不會在每次發布時變更。
當然,我們無法以這種方式重新命名「友善」的使用者介面網頁:將 index.html
檔案重新命名為 index.abcd12.html
,這麼做是不切實際的,因為您無法要求使用者每次載入網站時都前往新的網址!這些「友善」網址無法以這種方式重新命名及快取,這會讓我找到可能的折衷做法。
中間地帶
在快取方面,顯然有中庸之道。我提出了兩種極端的做法:永遠不快取或永遠快取。您可能會想將許多檔案暫時快取,例如我前面提到的「友善」網址。
如果您想快取這些「友善」網址及其 HTML,建議您考量這些網址包含哪些依附元件、這些網址如何快取,以及快取這些網址一段時間可能對您造成的影響。我們來看看包含以下圖片的 HTML 頁面:
<img src="/images/foo.jpeg" loading="lazy" />
如果您透過刪除或變更此延遲載入圖片來更新或變更網站,查看快取 HTML 版本的使用者可能會看到錯誤或缺少圖片,因為他們在重新造訪網站時,仍會快取原始 /images/foo.jpeg
。
只要你小心操作,這項政策可能不會對你造成影響。不過,請務必記住,當使用者快取網站時,網站就不再只存在於伺服器上。而是可能存在於使用者瀏覽器快取的片段中。
一般來說,大多數快取指南都會提到這類設定,例如您要快取一小時、數小時等等。如要設定這類快取,請使用類似以下的標頭 (快取時間為 3600 秒,即一小時):
Cache-Control: max-age=3600,immutable,public
最後一點是,如果您正在製作時效性內容,使用者通常只會存取一次 (例如新聞文章),我認為這些內容不應快取,您應使用上述合理的預設值。我認為,我們經常高估快取的價值,而忽略使用者希望一律看到最新、最棒的內容,例如新聞報導或當前事件的重要更新。
非 HTML 選項
除了 HTML 之外,其他位於中間位置的檔案選項包括:
一般來說,請尋找不會影響其他人的資產
- 例如:避免使用 CSS,因為這會導致 HTML 呈現方式發生變更
用於時事文章的大型圖片
- 使用者可能不會多次造訪任何一篇文章,因此請勿永久快取相片或主圖片,以免浪費儲存空間
代表本身具有生命週期的資產
- 天氣相關的 JSON 資料可能每小時才發布一次,因此您可以將先前的結果快取一小時,因為在您指定的時間範圍內,這項資料不會變更
- 開放原始碼專案的建構作業可能會受到速率限制,因此請快取建構狀態圖片,直到狀態可能變更為止
摘要
當使用者第二次載入網站時,就代表他們對您有信心,並且想回訪網站,進一步瞭解您提供的服務。此時,您不只要縮短載入時間,還可以使用多種選項,確保瀏覽器只執行必要作業,以提供快速且最新的使用體驗。
快取並非網頁上的新概念,但可能需要合理的預設值。建議您在需要時使用預設值,並強烈選擇加入更完善的快取策略。感謝您閱讀本信!
另請參閱
如需 HTTP 快取的一般指南,請參閱「透過 HTTP 快取防止不必要的網路要求」。