之前的文章《深入解析vue中路由切換白屏的問(wèn)題(附代碼)》中,給大家了解了vue中路由切換白屏的問(wèn)題。下面本篇文章給大家了解HTTP緩存機(jī)制詳解,有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你們有所助。
Web
緩存大致可以分為:數(shù)據(jù)庫(kù)緩存、服務(wù)器端緩存(代理服務(wù)器緩存、CDN
緩存)、瀏覽器緩存。
瀏覽器緩存也包含很多內(nèi)容:HTTP
緩存、indexDB
、cookie
、localstorage
等等。 這里要說(shuō)的是http
緩存。
使用緩存的好處
-
減少了冗余的數(shù)據(jù)傳輸
-
緩解了網(wǎng)絡(luò)瓶頸的問(wèn)題
-
降低了對(duì)原始服務(wù)器的要求
-
降低了距離時(shí)延
術(shù)語(yǔ)
緩存命中率:從緩存中得到數(shù)據(jù)的請(qǐng)求數(shù)與所有請(qǐng)求數(shù)的比率。理想狀態(tài)是越高越好。
過(guò)期內(nèi)容:超過(guò)設(shè)置的有效時(shí)間,被標(biāo)記為“陳舊”的內(nèi)容。通常過(guò)期內(nèi)容不能用于回復(fù)客戶(hù)端的請(qǐng)求,必須重新向源服務(wù)器請(qǐng)求新的內(nèi)容或者驗(yàn)證緩存的內(nèi)容是否仍然準(zhǔn)備。
驗(yàn)證:驗(yàn)證緩存中的過(guò)期內(nèi)容是否仍然有效,驗(yàn)證通過(guò)的話(huà)刷新過(guò)期時(shí)間。
失效:失效就是把內(nèi)容從緩存中移除。當(dāng)內(nèi)容發(fā)生改變時(shí)就必須移除失效的內(nèi)容。
機(jī)制
策略
1)緩存存儲(chǔ)策略
緩存存儲(chǔ)策略決定了客戶(hù)端是否應(yīng)該存儲(chǔ)http
的response
。與緩存存儲(chǔ)有關(guān)的http header
主要為response header
中的Cache-Control
。該header
有下面幾個(gè)對(duì)應(yīng)的值:Public
、Private
、no-cache
、max-age
、no-store
。除了no-store
,其它幾種都會(huì)表明response
應(yīng)該被客戶(hù)端緩存。
指令 | 說(shuō)明 |
---|---|
Public | 所有內(nèi)容都將被緩存(客戶(hù)端和代理服務(wù)器都可緩存) |
Private | 內(nèi)容只緩存到私有緩存中(僅客戶(hù)端可以緩存,代理服務(wù)器不可緩存) |
max-age = xxx (xxx is numeric) | 緩存的內(nèi)容將在 xxx 秒后失效,失效前可以直接使用本地緩存,失效后必須向服務(wù)器確認(rèn)資源是否已經(jīng)改變。 |
no-store | 完全不在客戶(hù)端緩存 |
no-cache | 可以認(rèn)為等同于 max-age=0 的情況,即將 response 緩存在客戶(hù)端,但是之后每次都向服務(wù)器確認(rèn)資源是否已經(jīng)改變 |
通過(guò)Cache-Control:Public
設(shè)置我們可以將HTTP
響應(yīng)數(shù)據(jù)存儲(chǔ)到本地,但此時(shí)并不意味著后續(xù)瀏覽器會(huì)直接從緩存中讀取數(shù)據(jù)并使用, 因?yàn)樗鼰o(wú)法確定本地緩存的數(shù)據(jù)是否可用(可能已經(jīng)失效),需通過(guò)緩存過(guò)期策略來(lái)判斷
2)緩存過(guò)期策略
緩存過(guò)期策略決定了客戶(hù)端存儲(chǔ)在本地的緩存數(shù)據(jù)是否已過(guò)期,如未過(guò)期則可以直接使用本地存儲(chǔ)的數(shù)據(jù),否則就需要發(fā)請(qǐng)求到服務(wù)端嘗試重新獲取數(shù)據(jù)。 與緩存過(guò)期策略有關(guān)的http header 為Expires
。
Expires
表示緩存數(shù)據(jù)有效的絕對(duì)時(shí)間,告訴客戶(hù)端到了這個(gè)時(shí)間點(diǎn)后本地緩存就失效了,在這個(gè)時(shí)間內(nèi)客戶(hù)端可以不請(qǐng)求服務(wù)器而直接從本地緩存中使用已存儲(chǔ)的結(jié)果。
需要注意的是:no-cache和max-age=xxx
的優(yōu)先級(jí)高于Expires
,當(dāng)它們同時(shí)存在的時(shí)候,后者會(huì)被覆蓋掉。其次, 緩存數(shù)據(jù)過(guò)期只是告訴客戶(hù)端不能再直接從本地讀取緩存了,而是需要再發(fā)一次請(qǐng)求到服務(wù)器去確認(rèn)。具體什么情況下本地存儲(chǔ)的數(shù)據(jù)還可以繼續(xù)使用就與緩存對(duì)比策略有關(guān)了。
3)緩存對(duì)比策略
將緩存在客戶(hù)端的數(shù)據(jù)標(biāo)識(shí)發(fā)往服務(wù)端,服務(wù)端通過(guò)標(biāo)識(shí)來(lái)判斷客戶(hù)端緩存數(shù)據(jù)是否仍有效,進(jìn)而決定是否要重發(fā)數(shù)據(jù)??蛻?hù)端檢測(cè)到數(shù)據(jù)過(guò)期或?yàn)g覽器刷新后,會(huì)重新發(fā)起一個(gè) http 請(qǐng)求到服務(wù)器,服務(wù)器此時(shí)并不急于返回?cái)?shù)據(jù),而是看請(qǐng)求頭有沒(méi)有帶標(biāo)識(shí)(If-Modified-Since、If-None-Match
)過(guò)來(lái),如果判斷標(biāo)識(shí)仍然有效,則返回304
告訴客戶(hù)端取本地緩存數(shù)據(jù)來(lái)用即可(這里要注意的是你必須要在首次響應(yīng)時(shí)輸出相應(yīng)的頭信息(Last-Modified、ETags
)到客戶(hù)端)。 本地緩存數(shù)據(jù)即使被認(rèn)為過(guò)期,并不等于數(shù)據(jù)從此就沒(méi)用了。
緩存過(guò)期取值
存儲(chǔ)策略里面no-cache
等同于max-age=0
,假如服務(wù)端返回的響應(yīng)中沒(méi)有指明max-age
、no-cache
或Expires
時(shí),客戶(hù)端是否會(huì)緩存 http response
呢 ?通過(guò)Fiddler
、Charles
等抓包工具可以發(fā)現(xiàn),客戶(hù)端一樣會(huì)進(jìn)行緩存
其取值值為響應(yīng)頭中的Date
與Last-Modified
之間的差值的10%作為緩存有效時(shí)間
在Fiddler
的Caching
面板中可以看到
HTTP/1.1 Cache-Control Header is present: private HTTP Last-Modified Header is present: Tue, 08 Nov 2016 06:59:00 GMT No explicit HTTP Cache Lifetime information was provided. Heuristic expiration policies suggest defaulting to: 10% of the delta between Last-Modified and Date. That's '05:15:02' so this response will heuristically expire 2016/11/11 0:46:01.
用一副圖來(lái)表示
緩存的控制
1)強(qiáng)制緩存
可以通過(guò)Expires
,Cache-Control
來(lái)設(shè)定,Expires
指緩存過(guò)期的時(shí)間,超過(guò)了這個(gè)時(shí)間點(diǎn)就代表資源過(guò)期。有一個(gè)問(wèn)題是由于使用具體時(shí)間,如果時(shí)間表示出錯(cuò)或者沒(méi)有轉(zhuǎn)換到正確的時(shí)區(qū)都可能造成緩存生命周期出錯(cuò)。 并且Expires
是HTTP/1.0
的標(biāo)準(zhǔn),現(xiàn)在更傾向于用HTTP/1.1
中定義的Cache-Control
。兩個(gè)同時(shí)存在時(shí)也是Cache-Control
的優(yōu)先級(jí)更高。
2)協(xié)商緩存
緩存的資源到期了,并不意味著資源內(nèi)容發(fā)生了改變,如果和服務(wù)器上的資源沒(méi)有差異,實(shí)際上沒(méi)有必要再次請(qǐng)求。客戶(hù)端和服務(wù)器端通過(guò)某種驗(yàn)證機(jī)制驗(yàn)證當(dāng)前請(qǐng)求資源是否可以使用緩存。 瀏覽器第一次請(qǐng)求數(shù)據(jù)之后會(huì)將數(shù)據(jù)和響應(yīng)頭部的緩存標(biāo)識(shí)存儲(chǔ)起來(lái)。再次請(qǐng)求時(shí)會(huì)帶上存儲(chǔ)的頭部字段,服務(wù)器端驗(yàn)證是否可用。如果返回304 Not Modified
,代表資源沒(méi)有發(fā)生改變可以使用緩存的數(shù)據(jù),獲取新的過(guò)期時(shí)間。反之返回200
就相當(dāng)于重新請(qǐng)求了一遍資源并替換舊資源。
Last-modified/If-Modified-Since
Last-modified:
服務(wù)器端資源的最后修改時(shí)間,響應(yīng)頭部會(huì)帶上這個(gè)標(biāo)識(shí)。第一次請(qǐng)求之后,瀏覽器記錄這個(gè)時(shí)間,再次請(qǐng)求時(shí),請(qǐng)求頭部帶上If-Modified-Since
即為之前記錄下的時(shí)間。服務(wù)器端收到帶If-Modified-Since
的請(qǐng)求后會(huì)去和資源的最后修改時(shí)間對(duì)比。若修改過(guò)就返回最新資源,狀態(tài)碼200
,若沒(méi)有修改過(guò)則返回304
。
Etag/If-None-Match
由服務(wù)器端上生成的一段hash
字符串,第一次請(qǐng)求時(shí)響應(yīng)頭帶上ETag: abcd
,之后的請(qǐng)求中帶上If-None-Match: abcd
,服務(wù)器檢查ETag
,返回304
或200
。
關(guān)于 last-modified 和 Etag 區(qū)別
-
某些服務(wù)器不能精確得到資源的最后修改時(shí)間,這樣就無(wú)法通過(guò)最后修改時(shí)間判斷資源是否更新。
-
Last-modified
只能精確到秒。 -
一些資源的最后修改時(shí)間改變了,但是內(nèi)容沒(méi)改變,使用
Last-modified
看不出內(nèi)容沒(méi)有改變。 -
Etag
的精度比Last-modified
高,屬于強(qiáng)驗(yàn)證,要求資源字節(jié)級(jí)別的一致,優(yōu)先級(jí)高。如果服務(wù)器端有提供ETag
的話(huà),必須先對(duì)ETag
進(jìn)行Conditional Request
。
注意:實(shí)際使用ETag/Last-modified
要注意保持一致性,做負(fù)載均衡和反向代理的話(huà)可能會(huì)出現(xiàn)不一致的情況。計(jì)算ETag
也是需要占用資源的,如果修改不是過(guò)于頻繁,看自己的需求用Cache-Control
是否可以滿(mǎn)足。
實(shí)際應(yīng)用
首先要明確哪些內(nèi)容適合被緩存哪些不適合。
考慮緩存的內(nèi)容:css
樣式文件,js
文件,logo
、圖標(biāo),html
文件,可以下載的內(nèi)容一些不應(yīng)該被緩存的內(nèi)容:業(yè)務(wù)敏感的GET請(qǐng)求
可緩存的內(nèi)容又分為幾種不同的情況:
不經(jīng)常改變的文件:給max-age
設(shè)置一個(gè)較大的值,一般設(shè)置max-age=31536000
比如引入的一些第三方文件、打包出來(lái)的帶有hash
后綴css
、js
文件。一般來(lái)說(shuō)文件內(nèi)容改變了,會(huì)更新版本號(hào)、hash
值,相當(dāng)于請(qǐng)求另一個(gè)文件。 標(biāo)準(zhǔn)中規(guī)定max-age
的值最大不超過(guò)一年,所以設(shè)成max-age=31536000
。至于過(guò)期內(nèi)容,緩存區(qū)會(huì)將一段時(shí)間沒(méi)有使用的文件刪除掉。
[完]
推薦學(xué)習(xí):Html5視頻教程