經過網絡獲取內容既緩慢,成本又高:大的響應須要在客戶端和服務器之間進行屢次往返通訊,這拖延了瀏覽器可使用和處理內容的時間,同時也增長了訪問者的數據成本。所以,緩存和重用之前獲取的資源的能力成爲優化性能很關鍵的一個方面。css
好消息是每一個瀏覽器都實現了 HTTP 緩存! 咱們所要作的就是,確保每一個服務器響應都提供正確的 HTTP 頭指令,以指導瀏覽器什麼時候能夠緩存響應以及能夠緩存多久。瀏覽器
Note: 若是在應用中使用 Webview 來獲取和顯示網頁內容,可能須要提供額外的配置標誌,以確保啓用了 HTTP 緩存,並根據用途設置了合理的緩存大小,同時,確保緩存持久化。查看平臺文檔並確認您的設置!緩存
服務器在返回響應時,還會發出一組 HTTP 頭,用來描述內容類型、長度、緩存指令、驗證令牌等。例如,在上圖的交互中,服務器返回了一個 1024 字節的響應,指導客戶端緩存響應長達 120 秒,並提供驗證令牌(x234dff),在響應過時以後,能夠用來驗證資源是否被修改。服務器
服務器經過 ETag HTTP 頭傳遞驗證令牌 經過驗證令牌能夠進行高效的資源更新檢查:若是資源未更改,則不會傳輸任何數據。 讓咱們假設在首次獲取資源 120 秒以後,瀏覽器又對該資源發起了新請求。首先,瀏覽器會檢查本地緩存並找到以前的響應,不幸的是,這個響應如今已經'過時',沒法在使用。此時,瀏覽器也能夠直接發出新請求,獲取新的完整響應,可是這樣作效率較低,由於若是資源未被更改過,咱們就沒有理由再去下載與緩存中已有的徹底相同的字節。網絡
這就是 ETag 頭中指定的驗證令牌所要解決的問題:服務器會生成並返回一個隨機令牌,一般是文件內容的哈希值或者某個其餘指紋碼。客戶端沒必要了解指紋碼是如何生成的,只須要在下一個請求中將其發送給服務器:若是指紋碼仍然一致,說明資源未被修改,咱們就能夠跳過下載。函數
在上面的例子中,客戶端自動在If-None-MatchHTTP 請求頭中提供 ETag 令牌,服務器針對當前的資源檢查令牌,若是未被修改過,則返回304 Not Modified響應,告訴瀏覽器緩存中的響應未被修改過,能夠再延用 120 秒。注意,咱們沒必要再次下載響應 - 這節約了時間和帶寬。性能
做爲網絡開發人員,您如何利用高效的從新驗證? 瀏覽器代替咱們完成了全部的工做:自動檢測是否已指定了驗證令牌,並會將驗證令牌附加到發出的請求上,根據從服務器收到的響應,在必要時更新緩存時間戳。實際上,咱們惟一要作的就是確保服務器提供必要的 ETag 令牌:查看服務器文檔中是否有必要的配置標誌。優化
Note: 提示:HTML5 Boilerplate 項目包含了全部最流行的服務器的配置文件樣例,而且爲每一個配置標誌和設置都提供了詳細的註釋:在列表中找到您喜歡的服務器,查找適合的設置,而後複製/確認您的服務器配置了推薦的設置。網站
每一個資源均可以經過 Cache-Control HTTP 頭來定義本身的緩存策略 Cache-Control 指令控制誰在什麼條件下能夠緩存響應以及能夠緩存多久 最好的請求是沒必要與服務器進行通訊的請求:經過響應的本地副本,咱們能夠避免全部的網絡延遲以及數據傳輸的數據成本。爲此,HTTP 規範容許服務器返回 一系列不一樣的 Cache-Control 指令,控制瀏覽器或者其餘中繼緩存如何緩存某個響應以及緩存多長時間。設計
Note: Cache-Control 頭在 HTTP/1.1 規範中定義,取代了以前用來定義響應緩存策略的頭(例如 Expires)。當前的全部瀏覽器都支持 Cache-Control,所以,使用它就夠了。
no-cache表示必須先與服務器確認返回的響應是否被更改,而後才能使用該響應來知足後續對同一個網址的請求。所以,若是存在合適的驗證令牌 (ETag),no-cache 會發起往返通訊來驗證緩存的響應,若是資源未被更改,能夠避免下載。
相比之下,no-store更加簡單,直接禁止瀏覽器和全部中繼緩存存儲返回的任何版本的響應 - 例如:一個包含我的隱私數據或銀行數據的響應。每次用戶請求該資源時,都會向服務器發送一個請求,每次都會下載完整的響應。
若是響應被標記爲public,即便有關聯的 HTTP 認證,甚至響應狀態碼沒法正常緩存,響應也能夠被緩存。大多數狀況下,public不是必須的,由於明確的緩存信息(例如max-age)已表示 響應能夠被緩存。
相比之下,瀏覽器能夠緩存private響應,可是一般只爲單個用戶緩存,所以,不容許任何中繼緩存對其進行緩存 - 例如,用戶瀏覽器能夠緩存包含用戶私人信息的 HTML 網頁,可是 CDN 不能緩存。
該指令指定從當前請求開始,容許獲取的響應被重用的最長時間(單位爲秒) - 例如:max-age=60表示響應能夠再緩存和重用 60 秒。
緩存決策樹
按照上面的決策樹來肯定您的應用使用的特定資源或一組資源的最優緩存策略。理想狀況下,目標應該是在客戶端上緩存儘量多的響應、緩存儘量長的時間,而且爲每一個響應提供驗證令牌,以便進行高效的從新驗證。
public
的)緩存長達一天(60 秒 x 60 分 x 24 小時)審查您的網頁,肯定哪些資源能夠被緩存,並確保能夠返回正確的 Cache-Control 和 ETag 頭。
在資源"過時"以前,將一直使用本地緩存的響應 經過將文件內容指紋碼嵌入網址,咱們能夠強制客戶端更新到新版的響應 爲了得到最佳性能,每一個應用須要定義本身的緩存層級 瀏覽器發出的全部 HTTP 請求會首先被路由到瀏覽器的緩存,以查看是否緩存了能夠用於實現請求的有效響應。若是有匹配的響應,會直接從緩存中讀取響應,這樣就避免了網絡延遲以及傳輸產生的數據成本。然而,若是咱們但願更新或廢棄已緩存的響應,該怎麼辦?
例如,假設咱們已經告訴訪問者某個 CSS 樣式表緩存長達 24 小時 (max-age=86400),可是設計人員剛剛提交了一個更新,咱們但願全部用戶都能使用。咱們該如何通知全部訪問者緩存的 CSS 副本已過期,須要更新緩存? 這是一個欺騙性的問題 - 實際上,至少在不更改資源網址的狀況下,咱們作不到。
一旦瀏覽器緩存了響應,在過時之前,將一直使用緩存的版本,這是由 max-age 或者 expires 指定的,或者直到由於某些緣由從緩存中刪除,例如用戶清除了瀏覽器緩存。所以,在構建網頁時,不一樣的用戶可能使用的是文件的不一樣版本;剛獲取該資源的用戶將使用新版本,而緩存過以前副本(可是依然有效)的用戶將繼續使用舊版本的響應。
因此,咱們如何才能魚和熊掌兼得:客戶端緩存和快速更新? 很簡單,在資源內容更改時,咱們能夠更改資源的網址,強制用戶下載新響應。一般狀況下,能夠經過在文件名中嵌入文件的指紋碼(或版本號)來實現 - 例如 style.x234dff.css。
由於可以定義每一個資源的緩存策略,因此,咱們能夠定義'緩存層級',這樣,不但能夠控制每一個響應的緩存時間,還能夠控制訪問者看到新版本的速度。例如,咱們一塊兒分析一下上面的例子:
HTML 被標記成no-cache,這意味着瀏覽器在每次請求時都會從新驗證文檔,若是內容更改,會獲取最新版本。同時,在 HTML 標記中,咱們在 CSS 和 JavaScript 資源的網址中嵌入指紋碼:若是這些文件的內容更改,網頁的 HTML 也會隨之更改,並將下載 HTML 響應的新副本。 容許瀏覽器和中繼緩存(例如 CDN)緩存 CSS,過時時間設置爲 1 年。注意,咱們能夠放心地使用 1 年的'遠期過時',由於咱們在文件名中嵌入了文件指紋碼:若是 CSS 更新,網址也會隨之更改。 JavaScript 過時時間也設置爲 1 年,可是被標記爲 private,也許是由於包含了 CDN 不該緩存的一些用戶私人數據。 緩存圖片時不包含版本或惟一指紋碼,過時時間設置爲 1 天。 組合使用 ETag、Cache-Control 和惟一網址,咱們能夠提供最佳的方案:較長的過時時間,控制能夠緩存響應的位置,以及按需更新。
不存在最佳的緩存策略。根據您的通訊模式、提供的數據類型以及應用特定的數據更新要求,必須定義和配置每一個資源最適合的設置以及總體的'緩存層級'。