轉(zhuǎn)載自https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
通過網(wǎng)絡獲取內(nèi)容既速度緩慢又開銷巨大捻爷。較大的響應需要在客戶端與服務器之間進行多次往返通信份企,這會延遲瀏覽器獲得和處理內(nèi)容的時間巡莹,還會增加訪問者的流量費用降宅。因此,緩存并重復利用之前獲取的資源的能力成為性能優(yōu)化的一個關鍵方面腰根。
好在每個瀏覽器都自帶了 HTTP 緩存實現(xiàn)功能额嘿。您只需要確保每個服務器響應都提供正確的 HTTP 標頭指令,以指示瀏覽器何時可以緩存響應以及可以緩存多久东帅。
注:如果您在應用中使用 Webview 來獲取和顯示網(wǎng)頁內(nèi)容球拦,可能需要提供額外的配置標志帐我,以確保 HTTP 緩存得到啟用愧膀、其大小根據(jù)用例進行了合理設置并且緩存將持久保存檩淋。務必查看平臺文檔并確認您的設置!
當服務器返回響應時碳柱,還會發(fā)出一組 HTTP 標頭熬芜,用于描述響應的內(nèi)容類型涎拉、長度、緩存指令鼓拧、驗證令牌等季俩。例如,在上圖的交互中店归,服務器返回一個 1024 字節(jié)的響應酪我,指示客戶端將其緩存最多 120 秒,并提供一個驗證令牌(“x234dff”)秩伞,可在響應過期后用來檢查資源是否被修改欺矫。
通過 ETag 驗證緩存的響應
TL;DR
- 服務器使用 ETag HTTP 標頭傳遞驗證令牌汇陆。
- 驗證令牌可實現(xiàn)高效的資源更新檢查:資源未發(fā)生變化時不會傳送任何數(shù)據(jù)。
假定在首次獲取資源 120 秒后阅羹,瀏覽器又對該資源發(fā)起了新的請求。首先执庐,瀏覽器會檢查本地緩存并找到之前的響應导梆。遺憾的是,該響應現(xiàn)已過期递鹉,瀏覽器無法使用藏斩。此時狰域,瀏覽器可以直接發(fā)出新的請求并獲取新的完整響應。不過屈溉,這樣做效率較低抬探,因為如果資源未發(fā)生變化驶睦,那么下載與緩存中已有的完全相同的信息就毫無道理可言匿醒!
這正是驗證令牌(在 ETag 標頭中指定)旨在解決的問題。服務器生成并返回的隨機令牌通常是文件內(nèi)容的哈希值或某個其他指紋溉痢『⒈客戶端不需要了解指紋是如何生成的竹挡,只需在下一次請求時將其發(fā)送至服務器揪罕。如果指紋仍然相同宝泵,則表示資源未發(fā)生變化儿奶,您就可以跳過下載鳄抒。
在上例中许溅,客戶端自動在“If-None-Match” HTTP 請求標頭內(nèi)提供 ETag 令牌。服務器根據(jù)當前資源核對令牌娱仔。如果它未發(fā)生變化牲迫,服務器將返回“304 Not Modified”響應借卧,告知瀏覽器緩存中的響應未發(fā)生變化铐刘,可以再延用 120 秒镰吵。請注意,您不必再次下載響應盼产,這節(jié)約了時間和帶寬勺馆。
作為網(wǎng)絡開發(fā)者,您如何利用高效的重新驗證草穆?瀏覽器會替我們完成所有工作:它會自動檢測之前是否指定了驗證令牌悲柱,它會將驗證令牌追加到發(fā)出的請求上豌鸡,并且它會根據(jù)從服務器接收的響應在必要時更新緩存時間戳轴总。我們唯一要做的就是確保服務器提供必要的 ETag 令牌怀樟。檢查您的服務器文檔中有無必要的配置標志往堡。
注:提示:HTML5 Boilerplate 項目包含所有最流行服務器的配置文件樣例共耍,其中為每個配置標志和設置都提供了詳細的注解痹兜。在列表中找到您喜愛的服務器字旭,查找合適的設置遗淳,然后復制/確認您的服務器配置了推薦的設置。
Cache-Control
TL;DR
- 每個資源都可通過 Cache-Control HTTP 標頭定義其緩存策略
- Cache-Control 指令控制誰在什么條件下可以緩存響應以及可以緩存多久拆讯。
從性能優(yōu)化的角度來說养叛,最佳請求是無需與服務器通信的請求:您可以通過響應的本地副本消除所有網(wǎng)絡延遲,以及避免數(shù)據(jù)傳送的流量費用弃甥。為實現(xiàn)此目的爽室,HTTP 規(guī)范允許服務器返回 Cache-Control 指令肮之,這些指令控制瀏覽器和其他中間緩存如何緩存各個響應以及緩存多久。
注:Cache-Control 標頭是在 HTTP/1.1 規(guī)范中定義的,取代了之前用來定義響應緩存策略的標頭(例如 Expires)丑瞧。所有現(xiàn)代瀏覽器都支持 Cache-Control,因此稽屏,使用它就夠了狐榔。
“no-cache”和“no-store”
“no-cache”表示必須先與服務器確認返回的響應是否發(fā)生了變化,然后才能使用該響應來滿足后續(xù)對同一網(wǎng)址的請求庵楷。因此楣颠,如果存在合適的驗證令牌 (ETag)蜓斧,no-cache 會發(fā)起往返通信來驗證緩存的響應挎春,但如果資源未發(fā)生變化直奋,則可避免下載脚线。
相比之下邮绿,“no-store”則要簡單得多船逮。它直接禁止瀏覽器以及所有中間緩存存儲任何版本的返回響應挖胃,例如酱鸭,包含個人隱私數(shù)據(jù)或銀行業(yè)務數(shù)據(jù)的響應凹髓。每次用戶請求該資產(chǎn)時饵沧,都會向服務器發(fā)送請求捷泞,并下載完整的響應锁右。
“public”與“private”
如果響應被標記為“public”咏瑟,則即使它有關聯(lián)的 HTTP 身份驗證码泞,甚至響應狀態(tài)代碼通常無法緩存,也可以緩存響應宋舷。大多數(shù)情況下祝蝠,“public”不是必需的绎狭,因為明確的緩存信息(例如“max-age”)已表示響應是可以緩存的儡嘶。
相比之下承疲,瀏覽器可以緩存“private”響應。不過啼辣,這些響應通常只為單個用戶緩存,因此不允許任何中間緩存對其進行緩存富弦。例如腕柜,用戶的瀏覽器可以緩存包含用戶私人信息的 HTML 網(wǎng)頁,但 CDN 卻不能緩存唉铜。
“max-age”
指令指定從請求的時間開始潭流,允許獲取的響應被重用的最長時間(單位:秒)。例如熬甫,“max-age=60”表示可在接下來的 60 秒緩存和重用響應椿肩。
定義最佳 Cache-Control 策略
按照以上決策樹為您的應用使用的特定資源或一組資源確定最佳緩存策略。在理想的情況下盖矫,您的目標應該是在客戶端上緩存盡可能多的響應辈双,緩存盡可能長的時間,并且為每個響應提供驗證令牌证芭,以實現(xiàn)高效的重新驗證。
根據(jù) HTTP Archive,在排名最高的 300,000 個網(wǎng)站(按照 Alexa 排名)中泛源,所有下載的響應中幾乎有半數(shù)可由瀏覽器緩存达箍,這可以大量減少重復的網(wǎng)頁瀏覽和訪問。當然,這并不意味著您的特定應用有 50% 的資源可以緩存邻辉。一些網(wǎng)站的資源 90% 以上都可以緩存,而其他網(wǎng)站可能有許多私密或時效要求高的數(shù)據(jù)根本無法緩存吱瘩。
請審核您的網(wǎng)頁蜜徽,確定哪些資源可以緩存,并確保它們返回正確的 Cache-Control 和 ETag 標頭怜械。
廢棄和更新緩存的響應
TL;DR
- 在資源“過期”之前峡扩,將一直使用本地緩存的響應教届。
- 您可以通過在網(wǎng)址中嵌入文件內(nèi)容指紋,強制客戶端更新到新版本的響應。
- 為獲得最佳性能,每個應用都需要定義自己的緩存層次結構家夺。
瀏覽器發(fā)出的所有 HTTP 請求會首先路由到瀏覽器緩存惨好,以確認是否緩存了可用于滿足請求的有效響應昧狮。如果有匹配的響應合住,則從緩存中讀取響應笨使,這樣就避免了網(wǎng)絡延遲和傳送產(chǎn)生的流量費用。
不過,如果您想更新或廢棄緩存的響應,該怎么辦派继?例如认轨,假定您已告訴訪問者將某個 CSS 樣式表緩存長達 24 小時 (max-age=86400)昨稼,但設計人員剛剛提交了一個您希望所有用戶都能使用的更新霍掺。您該如何通知擁有現(xiàn)在“已過時”的 CSS 緩存副本的所有訪問者更新其緩存牙丽?在不更改資源網(wǎng)址的情況下,您做不到铜涉。
瀏覽器緩存響應后,緩存的版本將一直使用到過期(由 max-age 或 expires 決定)盖彭,或一直使用到由于某種其他原因從緩存中刪除纹烹,例如用戶清除了瀏覽器緩存。因此召边,構建網(wǎng)頁時铺呵,不同的用戶可能最終使用的是文件的不同版本;剛獲取了資源的用戶將使用新版本的響應掌实,而緩存了早期(但仍有效)副本的用戶將使用舊版本的響應陪蜻。
所以,如何才能魚和熊掌兼得:客戶端緩存和快速更新贱鼻?您可以在資源內(nèi)容發(fā)生變化時更改它的網(wǎng)址,強制用戶下載新響應滋将。通常情況下邻悬,可以通過在文件名中嵌入文件的指紋或版本號來實現(xiàn) - 例如 style.x234dff.css。
因為能夠定義每個資源的緩存策略随闽,所以您可以定義“緩存層次結構”父丰,這樣不但可以控制每個響應的緩存時間,還可以控制訪問者看到新版本的速度掘宪。為了進行說明蛾扇,我們一起分析一下上面的示例:
- HTML 被標記為“no-cache”,這意味著瀏覽器在每次請求時都始終會重新驗證文檔魏滚,并在內(nèi)容變化時獲取最新版本镀首。此外,在 HTML 標記內(nèi)鼠次,您在 CSS 和 JavaScript 資產(chǎn)的網(wǎng)址中嵌入指紋:如果這些文件的內(nèi)容發(fā)生變化更哄,網(wǎng)頁的 HTML 也會隨之改變,并會下載 HTML 響應的新副本腥寇。
- 允許瀏覽器和中間緩存(例如 CDN)緩存 CSS成翩,并將 CSS 設置為 1 年后到期。請注意赦役,您可以放心地使用 1 年的“遠期過期”麻敌,因為您在文件名中嵌入了文件的指紋:CSS 更新時網(wǎng)址也會隨之變化。
- JavaScript 同樣設置為 1 年后到期掂摔,但標記為 private术羔,這或許是因為它包含的某些用戶私人數(shù)據(jù)是 CDN 不應緩存的职辅。
- 圖像緩存時不包含版本或唯一指紋,并設置為 1 天后到期聂示。
您可以組合使用 ETag域携、Cache-Control 和唯一網(wǎng)址來實現(xiàn)一舉多得:較長的過期時間、控制可以緩存響應的位置以及隨需更新鱼喉。
緩存檢查清單
不存在什么最佳緩存策略秀鞭。您需要根據(jù)通信模式、提供的數(shù)據(jù)類型以及應用特定的數(shù)據(jù)更新要求扛禽,為每個資源定義和配置合適的設置锋边,以及整體的“緩存層次結構”。
在制定緩存策略時编曼,您需要牢記下面這些技巧和方法:
- 使用一致的網(wǎng)址:如果您在不同的網(wǎng)址上提供相同的內(nèi)容豆巨,將會多次獲取和存儲這些內(nèi)容。提示:請注意掐场,網(wǎng)址區(qū)分大小寫往扔。
- 確保服務器提供驗證令牌 (ETag):有了驗證令牌,當服務器上的資源未發(fā)生變化時熊户,就不需要傳送相同的字節(jié)萍膛。
- 確定中間緩存可以緩存哪些資源:對所有用戶的響應完全相同的資源非常適合由 CDN 以及其他中間緩存進行緩存。
- 為每個資源確定最佳緩存周期:不同的資源可能有不同的更新要求嚷堡。為每個資源審核并確定合適的 max-age蝗罗。
- 確定最適合您的網(wǎng)站的緩存層次結構:您可以通過為 HTML 文檔組合使用包含內(nèi)容指紋的資源網(wǎng)址和短時間或 no-cache 周期,來控制客戶端獲取更新的速度蝌戒。
- 最大限度減少攪動:某些資源的更新比其他資源頻繁串塑。如果資源的特定部分(例如 JavaScript 函數(shù)或 CSS 樣式集)會經(jīng)常更新,可以考慮將其代碼作為單獨的文件提供北苟。這樣一來桩匪,每次獲取更新時,其余內(nèi)容(例如變化不是很頻繁的內(nèi)容庫代碼)可以從緩存獲取粹淋,從而最大限度減少下載的內(nèi)容大小吸祟。