HTTP 緩存

轉: https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

通過網絡提取內容既速度緩慢又開銷巨大。 較大的響應需要在客戶端與服務器之間進行多次往返通信,這會延遲瀏覽器獲得和處理內容的時間,還會增加訪問者的流量費用。 因此,緩存並重複利用之前獲取的資源的能力成爲性能優化的一個關鍵方面。

好在每個瀏覽器都自帶了 HTTP 緩存實現功能。 您只需要確保每個服務器響應都提供正確的 HTTP 標頭指令,以指示瀏覽器何時可以緩存響應以及可以緩存多久。

注:如果您在應用中使用 Webview 來獲取和顯示網頁內容,可能需要提供額外的配置標誌,以確保 HTTP 緩存得到啓用、其大小根據用例進行了合理設置並且緩存將持久保存。 務必查看平臺文檔並確認您的設置!

 

當服務器返回響應時,還會發出一組 HTTP 標頭,用於描述響應的內容類型、長度、緩存指令、驗證令牌等。 例如,在上圖的交互中,服務器返回一個 1024 字節的響應,指示客戶端將其緩存最多 120 秒,並提供一個驗證令牌(“x234dff”),可在響應過期後用來檢查資源是否被修改。

通過 ETag 驗證緩存的響應

TL;DR

  • 服務器使用 ETag HTTP 標頭傳遞驗證令牌。
  • 驗證令牌可實現高效的資源更新檢查:資源未發生變化時不會傳送任何數據。

假定在首次提取資源 120 秒後,瀏覽器又對該資源發起了新的請求。 首先,瀏覽器會檢查本地緩存並找到之前的響應。 遺憾的是,該響應現已過期,瀏覽器無法使用。 此時,瀏覽器可以直接發出新的請求並獲取新的完整響應。 不過,這樣做效率較低,因爲如果資源未發生變化,那麼下載與緩存中已有的完全相同的信息就毫無道理可言!

這正是驗證令牌(在 ETag 標頭中指定)旨在解決的問題。 服務器生成並返回的隨機令牌通常是文件內容的哈希值或某個其他指紋。 客戶端不需要了解指紋是如何生成的,只需在下一次請求時將其發送至服務器。 如果指紋仍然相同,則表示資源未發生變化,您就可以跳過下載。

 

 

在上例中,客戶端自動在“If-None-Match” HTTP 請求標頭內提供 ETag 令牌。 服務器根據當前資源覈對令牌。 如果它未發生變化,服務器將返回“304 Not Modified”響應,告知瀏覽器緩存中的響應未發生變化,可以再延用 120 秒。 請注意,您不必再次下載響應,這節約了時間和帶寬。

作爲網絡開發者,您如何利用高效的重新驗證?瀏覽器會替我們完成所有工作: 它會自動檢測之前是否指定了驗證令牌,它會將驗證令牌追加到發出的請求上,並且它會根據從服務器接收的響應在必要時更新緩存時間戳。 我們唯一要做的就是確保服務器提供必要的 ETag 令牌。 檢查您的服務器文檔中有無必要的配置標記。

注:提示:HTML5 Boilerplate 項目包含所有最流行服務器的配置文件樣例,其中爲每個配置標誌和設置都提供了詳細的註解。 在列表中找到您喜愛的服務器,查找合適的設置,然後複製/確認您的服務器配置了推薦的設置。

Cache-Control

TL;DR

  • 每個資源都可通過 Cache-Control HTTP 標頭定義其緩存策略
  • Cache-Control 指令控制誰在什麼條件下可以緩存響應以及可以緩存多久。

從性能優化的角度來說,最佳請求是無需與服務器通信的請求:您可以通過響應的本地副本消除所有網絡延遲,以及避免數據傳送的流量費用。 爲實現此目的,HTTP 規範允許服務器返回 Cache-Control 指令,這些指令控制瀏覽器和其他中間緩存如何緩存各個響應以及緩存多久。

注:Cache-Control 標頭是在 HTTP/1.1 規範中定義的,取代了之前用來定義響應緩存策略的標頭(例如 Expires)。 所有現代瀏覽器都支持 Cache-Control,因此,使用它就夠了。

 

“no-cache”和“no-store”

“no-cache”表示必須先與服務器確認返回的響應是否發生了變化,然後才能使用該響應來滿足後續對同一網址的請求。 因此,如果存在合適的驗證令牌 (ETag),no-cache 會發起往返通信來驗證緩存的響應,但如果資源未發生變化,則可避免下載。

相比之下,“no-store”則要簡單得多。 它直接禁止瀏覽器以及所有中間緩存存儲任何版本的返回響應,例如,包含個人隱私數據或銀行業務數據的響應。 每次用戶請求該資產時,都會向服務器發送請求,並下載完整的響應。

“public”與 “private”

如果響應被標記爲“public”,則即使它有關聯的 HTTP 身份驗證,甚至響應狀態代碼通常無法緩存,也可以緩存響應。 大多數情況下,“public”不是必需的,因爲明確的緩存信息(例如“max-age”)已表示響應是可以緩存的。

相比之下,瀏覽器可以緩存“private”響應。 不過,這些響應通常只爲單個用戶緩存,因此不允許任何中間緩存對其進行緩存。 例如,用戶的瀏覽器可以緩存包含用戶私人信息的 HTML 網頁,但 CDN 卻不能緩存。

“max-age”

指令指定從請求的時間開始,允許提取的響應被重用的最長時間(單位:秒)。 例如,“max-age=60”表示可在接下來的 60 秒緩存和重用響應。

定義最佳 Cache-Control 策略

 

按照以上決策樹爲您的應用使用的特定資源或一組資源確定最佳緩存策略。 在理想的情況下,您的目標應該是在客戶端上緩存儘可能多的響應,緩存儘可能長的時間,並且爲每個響應提供驗證令牌,以實現高效的重新驗證。

Cache-Control 指令和說明
max-age=86400 瀏覽器以及任何中間緩存均可將響應(如果是“public”響應)緩存長達 1 天(60 秒 x 60 分鐘 x 24 小時)。
private, max-age=600 客戶端的瀏覽器只能將響應緩存最長 10 分鐘(60 秒 x 10 分鐘)。
no-store 不允許緩存響應,每次請求都必須完整獲取。

根據 HTTP Archive,在排名最高的 300,000 個網站(按照 Alexa 排名)中,所有下載的響應中幾乎有半數可由瀏覽器緩存,這可以大量減少重複的網頁瀏覽和訪問。 當然,這並不意味着您的特定應用有 50% 的資源可以緩存。 一些網站的資源 90% 以上都可以緩存,而其他網站可能有許多私密或時效要求高的數據根本無法緩存。

請審覈您的網頁,確定哪些資源可以緩存,並確保其返回正確的 Cache-Control 和 ETag 標頭。

廢棄和更新緩存的響應

TL;DR

  • 在資源“過期”之前,將一直使用本地緩存的響應。
  • 您可以通過在網址中嵌入文件內容指紋,強制客戶端更新到新版本的響應。
  • 爲獲得最佳性能,每個應用都需要定義自己的緩存層次結構。

瀏覽器發出的所有 HTTP 請求會首先路由到瀏覽器緩存,以確認是否緩存了可用於滿足請求的有效響應。 如果有匹配的響應,則從緩存中讀取響應,這樣就避免了網絡延遲和傳送產生的流量費用。

不過,如果您想更新或廢棄緩存的響應,該怎麼辦?例如,假定您已告訴訪問者將某個 CSS 樣式表緩存長達 24 小時 (max-age=86400),但設計人員剛剛提交了一個您希望所有用戶都能使用的更新。 您該如何通知擁有現在“已過時”的 CSS 緩存副本的所有訪問者更新其緩存?在不更改資源網址的情況下,您做不到。

瀏覽器緩存響應後,緩存的版本將一直使用到過期(由 max-age 或 expires 決定),或一直使用到由於某種其他原因從緩存中刪除,例如用戶清除了瀏覽器緩存。 因此,構建網頁時,不同的用戶可能最終使用的是文件的不同版本;剛提取了資源的用戶將使用新版本的響應,而緩存了早期(但仍有效)副本的用戶將使用舊版本的響應。

如何才能魚和熊掌兼得:客戶端緩存和快速更新?您可以在資源內容發生變化時更改其網址,強制用戶下載新響應。 通常情況下,可以通過在文件名中嵌入文件的指紋或版本號來實現—例如 style.x234dff.css。

 

因爲能夠定義每個資源的緩存策略,所以您可以定義“緩存層次結構”,這樣不但可以控制每個響應的緩存時間,還可以控制訪問者看到新版本的速度。 爲了進行說明,我們一起分析一下上面的示例:

  • HTML 被標記爲“no-cache”,這意味着瀏覽器在每次請求時都始終會重新驗證文檔,並在內容變化時提取最新版本。 此外,在 HTML 標記內,您在 CSS 和 JavaScript 資產的網址中嵌入指紋:如果這些文件的內容發生變化,網頁的 HTML 也會隨之改變,並會下載 HTML 響應的新副本。
  • 允許瀏覽器和中間緩存(例如 CDN)緩存 CSS,並將 CSS 設置爲 1 年後到期。 請注意,您可以放心地使用 1 年的“遠期過期”,因爲您在文件名中嵌入了文件的指紋:CSS 更新時網址也會隨之變化。
  • JavaScript 同樣設置爲 1 年後到期,但標記爲 private,這或許是因爲它包含的某些用戶私人數據是 CDN 不應緩存的。
  • 圖像緩存時不包含版本或唯一指紋,並設置爲 1 天后到期。

您可以組合使用 ETag、Cache-Control 和唯一網址來實現一舉多得:較長的過期時間、控制可以緩存響應的位置以及隨需更新。

緩存檢查清單

不存在什麼最佳緩存策略。 您需要根據通信模式、提供的數據類型以及應用特定的數據更新要求,爲每個資源定義和配置合適的設置,以及整體的“緩存層次結構”。

在制定緩存策略時,您需要牢記下面這些技巧和方法:

  • 使用一致的網址:如果您在不同的網址上提供相同的內容,將會多次提取和存儲這些內容。 提示:請注意,網址區分大小寫
  • 確保服務器提供驗證令牌 (ETag):有了驗證令牌,當服務器上的資源未發生變化時,就不需要傳送相同的字節。
  • 確定中間緩存可以緩存哪些資源:對所有用戶的響應完全相同的資源非常適合由 CDN 以及其他中間緩存進行緩存。
  • 爲每個資源確定最佳緩存週期:不同的資源可能有不同的更新要求。 爲每個資源審覈並確定合適的 max-age。
  • 確定最適合您的網站的緩存層次結構:您可以通過爲 HTML 文檔組合使用包含內容指紋的資源網址和短時間或 no-cache 週期,來控制客戶端獲取更新的速度。
  • 最大限度減少攪動:某些資源的更新比其他資源頻繁。 如果資源的特定部分(例如 JavaScript 函數或 CSS 樣式集)會經常更新,可以考慮將其代碼作爲單獨的文件提供。 這樣一來,每次提取更新時,其餘內容(例如變化不是很頻繁的內容庫代碼)可以從緩存提取,從而最大限度減少下載的內容大小。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章