前端学习笔记--HTTP缓存
原文地址:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn
緩存并重用之前獲取的資源的能力是性能優(yōu)化的一個(gè)關(guān)鍵方面。
每個(gè)瀏覽器都自帶了 HTTP 緩存實(shí)現(xiàn)功能,只需要確保每個(gè)服務(wù)器響應(yīng)都提供正確的 HTTP 標(biāo)頭指令,以指示瀏覽器何時(shí)可以緩存響應(yīng)以及可以緩存多久。
?
HTTP 與瀏覽器交互的請(qǐng)求頭:
當(dāng)服務(wù)器返回響應(yīng)時(shí),還會(huì)發(fā)出一組 HTTP 標(biāo)頭,用于描述響應(yīng)的內(nèi)容類型、長(zhǎng)度、緩存指令、驗(yàn)證令牌等。例如,在上圖的交互中,服務(wù)器返回一個(gè) 1024 字節(jié)的響應(yīng),指示客戶端將其緩存最多 120 秒,并提供一個(gè)驗(yàn)證令牌(“x234dff”),可在響應(yīng)過期后用來檢查資源是否被修改。
?
通過ETag驗(yàn)證緩存的響應(yīng)
- 服務(wù)器使用ETag HTTP表頭傳遞驗(yàn)證令牌
- 驗(yàn)證令牌可以實(shí)現(xiàn)高效率的資源檢查:資源未發(fā)生變化時(shí)不會(huì)傳送任何數(shù)據(jù)
驗(yàn)證令牌的作用:
假定在首次獲取資源 120 秒后,瀏覽器又對(duì)該資源發(fā)起了新的請(qǐng)求。首先,瀏覽器會(huì)檢查本地緩存并找到之前的響應(yīng)。遺憾的是,該響應(yīng)現(xiàn)已過期,瀏覽器無法使用。此時(shí),瀏覽器可以直接發(fā)出新的請(qǐng)求并獲取新的完整響應(yīng)。不過,這樣做效率較低,因?yàn)槿绻Y源未發(fā)生變化,那么下載與緩存中已有的完全相同的信息就毫無道理可言!
這正是驗(yàn)證令牌(在 ETag 標(biāo)頭中指定)旨在解決的問題。服務(wù)器生成并返回的隨機(jī)令牌通常是文件內(nèi)容的哈希值或某個(gè)其他指紋。客戶端不需要了解指紋是如何生成的,只需在下一次請(qǐng)求時(shí)將其發(fā)送至服務(wù)器。如果指紋仍然相同,則表示資源未發(fā)生變化,您就可以跳過下載。 例如:
在上例中,客戶端自動(dòng)在“If-None-Match” HTTP 請(qǐng)求標(biāo)頭內(nèi)提供 ETag 令牌。服務(wù)器根據(jù)當(dāng)前資源核對(duì)令牌。如果它未發(fā)生變化,服務(wù)器將返回“304 Not Modified”響應(yīng),告知瀏覽器緩存中的響應(yīng)未發(fā)生變化,可以再延用 120 秒。請(qǐng)注意,您不必再次下載響應(yīng),這節(jié)約了時(shí)間和帶寬。
作為網(wǎng)絡(luò)開發(fā)者,如何利用高效的重新驗(yàn)證?瀏覽器會(huì)替我們完成所有工作:它會(huì)自動(dòng)檢測(cè)之前是否指定了驗(yàn)證令牌,它會(huì)將驗(yàn)證令牌追加到發(fā)出的請(qǐng)求上,并且它會(huì)根據(jù)從服務(wù)器接收的響應(yīng)在必要時(shí)更新緩存時(shí)間戳。我們唯一要做的就是確保服務(wù)器提供必要的 ETag 令牌。檢查服務(wù)器文檔中有無必要的配置標(biāo)志。
提示:HTML5 Boilerplate 項(xiàng)目包含所有最流行服務(wù)器的配置文件樣例,其中為每個(gè)配置標(biāo)志和設(shè)置都提供了詳細(xì)的注解。在列表中找到您喜愛的服務(wù)器,查找合適的設(shè)置,然后復(fù)制/確認(rèn)您的服務(wù)器配置了推薦的設(shè)置。
Cache-Control
- 每個(gè)資源都可通過 Cache-Control HTTP 標(biāo)頭定義其緩存策略
- Cache-Control 指令控制誰在什么條件下可以緩存響應(yīng)以及可以緩存多久。
從性能優(yōu)化的角度來說,最佳請(qǐng)求是無需與服務(wù)器通信的請(qǐng)求:可以通過響應(yīng)的本地副本消除所有網(wǎng)絡(luò)延遲,以及避免數(shù)據(jù)傳送的流量費(fèi)用。為實(shí)現(xiàn)此目的,HTTP 規(guī)范允許服務(wù)器返回?Cache-Control 指令,這些指令控制瀏覽器和其他中間緩存如何緩存各個(gè)響應(yīng)以及緩存多久。
注:Cache-Control 標(biāo)頭是在 HTTP/1.1 規(guī)范中定義的,取代了之前用來定義響應(yīng)緩存策略的標(biāo)頭(例如 Expires)。所有現(xiàn)代瀏覽器都支持 Cache-Control,因此,使用它就夠了。
命令:
“no-cache”和“no-store”
“no-cache”表示必須先與服務(wù)器確認(rèn)返回的響應(yīng)是否發(fā)生了變化,然后才能使用該響應(yīng)來滿足后續(xù)對(duì)同一網(wǎng)址的請(qǐng)求。因此,如果存在合適的驗(yàn)證令牌 (ETag),no-cache 會(huì)發(fā)起往返通信來驗(yàn)證緩存的響應(yīng),但如果資源未發(fā)生變化,則可避免下載。
相比之下,“no-store”則要簡(jiǎn)單得多。它直接禁止瀏覽器以及所有中間緩存存儲(chǔ)任何版本的返回響應(yīng),例如,包含個(gè)人隱私數(shù)據(jù)或銀行業(yè)務(wù)數(shù)據(jù)的響應(yīng)。每次用戶請(qǐng)求該資產(chǎn)時(shí),都會(huì)向服務(wù)器發(fā)送請(qǐng)求,并下載完整的響應(yīng)。
“public”與“private”
如果響應(yīng)被標(biāo)記為“public”,則即使它有關(guān)聯(lián)的 HTTP 身份驗(yàn)證,甚至響應(yīng)狀態(tài)代碼通常無法緩存,也可以緩存響應(yīng)。大多數(shù)情況下,“public”不是必需的,因?yàn)槊鞔_的緩存信息(例如“max-age”)已表示響應(yīng)是可以緩存的。
相比之下,瀏覽器可以緩存“private”響應(yīng)。不過,這些響應(yīng)通常只為單個(gè)用戶緩存,因此不允許任何中間緩存對(duì)其進(jìn)行緩存。例如,用戶的瀏覽器可以緩存包含用戶私人信息的 HTML 網(wǎng)頁(yè),但 CDN 卻不能緩存。
“max-age”
指令指定從請(qǐng)求的時(shí)間開始,允許獲取的響應(yīng)被重用的最長(zhǎng)時(shí)間(單位:秒)。例如,“max-age=60”表示可在接下來的 60 秒緩存和重用響應(yīng)。
定義最佳的Cache-Control 策略
按照以上決策樹為您的應(yīng)用使用的特定資源或一組資源確定最佳緩存策略。在理想的情況下,您的目標(biāo)應(yīng)該是在客戶端上緩存盡可能多的響應(yīng),緩存盡可能長(zhǎng)的時(shí)間,并且為每個(gè)響應(yīng)提供驗(yàn)證令牌,以實(shí)現(xiàn)高效的重新驗(yàn)證。
| max-age=86400 | 瀏覽器以及任何中間緩存均可將響應(yīng)(如果是“public”響應(yīng))緩存長(zhǎng)達(dá) 1 天(60 秒 x 60 分鐘 x 24 小時(shí))。 |
| private, max-age=600 | 客戶端的瀏覽器只能將響應(yīng)緩存最長(zhǎng) 10 分鐘(60 秒 x 10 分鐘)。 |
| no-store | 不允許緩存響應(yīng),每次請(qǐng)求都必須完整獲取。 |
?
根據(jù) HTTP Archive,在排名最高的 300,000 個(gè)網(wǎng)站(按照 Alexa 排名)中,所有下載的響應(yīng)中幾乎有半數(shù)可由瀏覽器緩存,這可以大量減少重復(fù)的網(wǎng)頁(yè)瀏覽和訪問。當(dāng)然,這并不意味著您的特定應(yīng)用有 50% 的資源可以緩存。一些網(wǎng)站的資源 90% 以上都可以緩存,而其他網(wǎng)站可能有許多私密或時(shí)效要求高的數(shù)據(jù)根本無法緩存。
審核網(wǎng)頁(yè),確定哪些資源可以緩存,并確保它們返回正確的 Cache-Control 和 ETag 標(biāo)頭。
廢棄和更新緩存的響應(yīng)
- 在資源“過期”之前,將一直使用本地緩存的響應(yīng)。
- 您可以通過在網(wǎng)址中嵌入文件內(nèi)容指紋,強(qiáng)制客戶端更新到新版本的響應(yīng)。
- 為獲得最佳性能,每個(gè)應(yīng)用都需要定義自己的緩存層次結(jié)構(gòu)。
瀏覽器發(fā)出的所有 HTTP 請(qǐng)求會(huì)首先路由到瀏覽器緩存,以確認(rèn)是否緩存了可用于滿足請(qǐng)求的有效響應(yīng)。如果有匹配的響應(yīng),則從緩存中讀取響應(yīng),這樣就避免了網(wǎng)絡(luò)延遲和傳送產(chǎn)生的流量費(fèi)用。
不過,如果想更新或廢棄緩存的響應(yīng),該怎么辦??例如,假定已告訴訪問者將某個(gè) CSS 樣式表緩存長(zhǎng)達(dá) 24 小時(shí) (max-age=86400),但設(shè)計(jì)人員剛剛提交了一個(gè)您希望所有用戶都能使用的更新。該如何通知擁有現(xiàn)在“已過時(shí)”的 CSS 緩存副本的所有訪問者更新其緩存?在不更改資源網(wǎng)址的情況下,做不到。
瀏覽器緩存響應(yīng)后,緩存的版本將一直使用到過期(由 max-age 或 expires 決定),或一直使用到由于某種其他原因從緩存中刪除,例如用戶清除了瀏覽器緩存。因此,構(gòu)建網(wǎng)頁(yè)時(shí),不同的用戶可能最終使用的是文件的不同版本;剛獲取了資源的用戶將使用新版本的響應(yīng),而緩存了早期(但仍有效)副本的用戶將使用舊版本的響應(yīng)。
所以,如何才能魚和熊掌兼得:客戶端緩存和快速更新??可以在資源內(nèi)容發(fā)生變化時(shí)更改它的網(wǎng)址,強(qiáng)制用戶下載新響應(yīng)。通常情況下,可以通過在文件名中嵌入文件的指紋或版本號(hào)來實(shí)現(xiàn) - 例如 style.x234dff.css。
因?yàn)槟軌蚨x每個(gè)資源的緩存策略,所以可以定義“緩存層次結(jié)構(gòu)”,這樣不但可以控制每個(gè)響應(yīng)的緩存時(shí)間,還可以控制訪問者看到新版本的速度。為了進(jìn)行說明,我們一起分析一下上面的示例:
- HTML 被標(biāo)記為“no-cache”,這意味著瀏覽器在每次請(qǐng)求時(shí)都始終會(huì)重新驗(yàn)證文檔,并在內(nèi)容變化時(shí)獲取最新版本。此外,在 HTML 標(biāo)記內(nèi),在 CSS 和 JavaScript 資產(chǎn)的網(wǎng)址中嵌入指紋:如果這些文件的內(nèi)容發(fā)生變化,網(wǎng)頁(yè)的 HTML 也會(huì)隨之改變,并會(huì)下載 HTML 響應(yīng)的新副本。
- 允許瀏覽器和中間緩存(例如 CDN)緩存 CSS,并將 CSS 設(shè)置為 1 年后到期。請(qǐng)注意,可以放心地使用 1 年的“遠(yuǎn)期過期”,因?yàn)樵谖募星度肓宋募闹讣y:CSS 更新時(shí)網(wǎng)址也會(huì)隨之變化。
- JavaScript 同樣設(shè)置為 1 年后到期,但標(biāo)記為 private,這或許是因?yàn)樗哪承┯脩羲饺藬?shù)據(jù)是 CDN 不應(yīng)緩存的。
- 圖像緩存時(shí)不包含版本或唯一指紋,并設(shè)置為 1 天后到期。
可以組合使用 ETag、Cache-Control 和唯一網(wǎng)址來實(shí)現(xiàn)一舉多得:較長(zhǎng)的過期時(shí)間、控制可以緩存響應(yīng)的位置以及隨需更新。
緩存檢查清單
不存在什么最佳緩存策略。需要根據(jù)通信模式、提供的數(shù)據(jù)類型以及應(yīng)用特定的數(shù)據(jù)更新要求,為每個(gè)資源定義和配置合適的設(shè)置,以及整體的“緩存層次結(jié)構(gòu)”。
在制定緩存策略時(shí),需要牢記下面這些技巧和方法:
- 使用一致的網(wǎng)址:如果在不同的網(wǎng)址上提供相同的內(nèi)容,將會(huì)多次獲取和存儲(chǔ)這些內(nèi)容。提示:請(qǐng)注意,網(wǎng)址區(qū)分大小寫。
- 確保服務(wù)器提供驗(yàn)證令牌 (ETag):有了驗(yàn)證令牌,當(dāng)服務(wù)器上的資源未發(fā)生變化時(shí),就不需要傳送相同的字節(jié)。
- 確定中間緩存可以緩存哪些資源:對(duì)所有用戶的響應(yīng)完全相同的資源非常適合由 CDN 以及其他中間緩存進(jìn)行緩存。
- 為每個(gè)資源確定最佳緩存周期:不同的資源可能有不同的更新要求。為每個(gè)資源審核并確定合適的 max-age。
- 確定最適合的網(wǎng)站的緩存層次結(jié)構(gòu):可以通過為 HTML 文檔組合使用包含內(nèi)容指紋的資源網(wǎng)址和短時(shí)間或 no-cache 周期,來控制客戶端獲取更新的速度。
- 最大限度減少攪動(dòng):某些資源的更新比其他資源頻繁。如果資源的特定部分(例如 JavaScript 函數(shù)或 CSS 樣式集)會(huì)經(jīng)常更新,可以考慮將其代碼作為單獨(dú)的文件提供。這樣一來,每次獲取更新時(shí),其余內(nèi)容(例如變化不是很頻繁的內(nèi)容庫(kù)代碼)可以從緩存獲取,從而最大限度減少下載的內(nèi)容大小。
總結(jié)
以上是生活随笔為你收集整理的前端学习笔记--HTTP缓存的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: css实现3D立方体旋转特效
- 下一篇: HTML 部分常用属性、组成属性|...