瀏覽器緩存

Web緩存分為很多種,比如數(shù)據(jù)庫緩存,代理服務(wù)器緩存,還有我們熟悉的CDN緩存,以及瀏覽器緩存。

緩存的重要性不用多說了吧,例如chrome會把緩存的文件保存在一個叫User Data的文件夾下,下次頁面加載同樣資源時,可以直接從本地讀取,不必通過HTTP從服務(wù)器端再次下載資源,大大加快了頁面的響應(yīng)速度。

本篇主要介紹一下瀏覽器緩存:

  • HTTP Rresponse Header
  • Cache-Control
  • Expires
  • Last-modified
  • ETag
  • 實時更新緩存
  • 緩存策略

Cache-Control

Cache-Control用于定義資源的緩存策略??梢灾付?code>no-store,no-cache,public,privatemax-gae,s-maxage

no-store絕對禁止緩存,每次請求資源都要從服務(wù)器重新獲取。常見于包含隱私數(shù)據(jù)或銀行數(shù)據(jù)等場合。

no-cache表示不管max-age過不過期,每次都要向服務(wù)器重新驗證資源是否被更改。只有服務(wù)器端確認(rèn)資源未被修改后(如后面會介紹的Last-modified或ETag),才能使用本地緩存。

public(默認(rèn)就是public)允許代理服務(wù)器緩存資源,以供多用戶間共享。

private不允許代理服務(wù)器緩存該資源,用戶間不共享,如HTTP認(rèn)證響應(yīng)會自動設(shè)為private

max-age緩存最大有效時間。單位是秒,從被請求時開始計時,這樣可以避免時鐘同步問題。因為原先用于緩存的Expires需要服務(wù)器和客戶端時鐘嚴(yán)格同步,因此HTTP 1.1引入了cache-control: max-age來避免時鐘同步的限制。因此當(dāng)cache-control: max-age和Expires同時出現(xiàn),Expires將被忽略。

s-maxage只適用于共享緩存如CDN緩存。

如圖服務(wù)器端收到請求后,在HTTP Rresponse Header里將cache-control: max-age=120,表示該資源的有效時間為2分鐘。2分鐘內(nèi)客戶端如需再次使用該資源,可以直接從本地讀取,不需要再次向服務(wù)器發(fā)出請求了。

Cache-Control的判斷流程圖:

Expires

在HTTP1.1引入Cache-Control之前,用Expires設(shè)置緩存過期時間,告訴瀏覽器在過期時間前瀏覽器可以直接從本地讀取資源,不必再次向服務(wù)器請求。

但HTTP1.1之后用Cache-Control取代了Expires,如果為了兼容性cache-control: max-age和Expires同時出現(xiàn),Expires將被忽略

Last-modified

Last-modified是服務(wù)器告訴瀏覽器這個資源最后被修改的時間。

有什么用呢?例如瀏覽器根據(jù)cache-control: max-age或Expires發(fā)現(xiàn)緩存過期了,按理應(yīng)該向服務(wù)器重新請求資源。但如果資源內(nèi)容其實沒有變,重新請求資源太浪費了,用Last-modified可以優(yōu)化這個過程。

在有Last-Modified的情況下,瀏覽器會發(fā)送If-Modified-Since請求,服務(wù)器端比對請求里L(fēng)ast-modified時間和資源文件最后被修改時間是否一致。如果一致,服務(wù)器端回復(fù)304 Not Modified,這樣瀏覽器就能繼續(xù)使用本地的過期緩存了,節(jié)約了帶寬。如果不一致,服務(wù)器回復(fù)200 OK,重新發(fā)送資源給瀏覽器。

Last-modified作為一種優(yōu)化手段,需要和cache-control: max-age或Expires共同使用。

ETag

Last-modified作為一種優(yōu)化手段,還不夠完美,有時會有一些問題:

  1. 某些服務(wù)器不能精確得到資源的最后修改時間
  2. 如果資源修改非常頻繁,在秒以下的時間內(nèi)進(jìn)行修改,而Last-modified只能精確到秒
  3. 一些資源的最后修改時間變了,但其實內(nèi)容沒改變

因此引入了ETag作為Last-modified的進(jìn)階版來解決上面這些問題。服務(wù)端根據(jù)實體內(nèi)容生成一段hash字符串,用以標(biāo)識資源的狀態(tài)。具體生成的hash字符串服務(wù)器有自己的規(guī)范,如Apache中,默認(rèn)是對文件的索引節(jié)(INode),大小(Size)和最后修改時間(MTime)進(jìn)行hash后得到的。例如Etag: “5483ec7b-7c52”

ETag的原理和Last-modified類似,雖然瀏覽器根據(jù)cache-control: max-age或Expires發(fā)現(xiàn)緩存過期了,但如果資源其實沒有變的話,重新請求有點浪費。用ETag可以優(yōu)化這個過程。

在有ETag的情況下,瀏覽器會發(fā)送If-None-Match請求,服務(wù)器端將請求里ETag字符串和資源文件的ETag字符串進(jìn)行比較。如果一致,服務(wù)器端回復(fù)304 Not Modified,這樣瀏覽器就能繼續(xù)使用本地的過期緩存了,節(jié)約了帶寬。如果不一致,服務(wù)器回復(fù)200 OK,重新發(fā)送資源給瀏覽器。

ETag作為Last-modified的進(jìn)階版,同樣需要和cache-control: max-age或Expires共同使用。而且當(dāng)ETag和Last-modified同時存在時,Last-modified會被忽略,因此如果ETag匹配失敗,即使緩存的Last-Modified沒失效,也得到不到304 Not Modified。

如下圖,瀏覽器發(fā)現(xiàn)cache-control: max-age=120過期了,就向服務(wù)器發(fā)送If-None-Match請求,服務(wù)器發(fā)現(xiàn)資源未被修改過,因此回復(fù)304 Not Modified通知瀏覽器繼續(xù)使用本地緩存


ETag的問題在于使用網(wǎng)站服務(wù)器會使用資源的某些屬性來構(gòu)造它,但對于擁有多臺服務(wù)器的網(wǎng)站,如Apache和IIS使用的屬性不同,導(dǎo)致生成的hash值不同,會大大降低驗證的成功率。結(jié)果是,對于完全相同的資源,當(dāng)瀏覽器從Apache上獲取了資源,又向IIS發(fā)起Get請求,ETag是不會匹配的。用戶就無法收到更小更快的304,而是收到200正常去下載該資源。

如在多臺服務(wù)器上寄宿你的網(wǎng)站,且你使用默認(rèn)ETag配置的Apache或IIS,那么效率問題你必須面對。例如Apache用FileETag可從ETag中移除inode值,只留下大小和時間撮作為組件的ETag。IIS也有類似的ChangeNumber只留下時間撮作為組件的ETag。當(dāng)然也可以徹底移除ETag,如Apache上FileETag none

整體緩存的過程:


實時更新緩存

如果你改動了某資源,如CSS,但用戶本地的cache-control: max-age或Expires時間未到,用戶仍舊會使用舊的CSS。除非緩存過期,或用戶清理了瀏覽器緩存,否則你修改的資源文件是沒有辦法第一時間通知到用戶的。

如果想要實現(xiàn),只能修改資源文件路徑,例如將CSS文件名重命名為xxx-v2.css等。以此強(qiáng)制用戶重新加載最新版資源。

緩存策略

可以為不同類型的資源文件定制不同的緩存策略,如下圖:


HTML文件必須確保最新,因此定義成no-cache,這樣每次請求都會驗證該HTML文件是否最新

JS和CSS文件因為經(jīng)常會被修改,因此文件名嵌入指紋碼(也可以是版本號或時間戳)。每次修改文件后文件名均不同,相當(dāng)于HTML里加載不同的文件,強(qiáng)制用戶下載最新版。由于文件名里嵌入了指紋碼,可以放心大膽地將max-age設(shè)置1年。

JS里標(biāo)記為private,因為JS里可能會包含一些私人數(shù)據(jù)。

圖片因為不常變,所以文件名不必包含指紋碼,可以根據(jù)需要設(shè)置max-age

最后配合ETag可以使得緩存機(jī)制更高效。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容