理解HTTP緩存機(jī)制
?點(diǎn)擊上方藍(lán)字關(guān)注我們,

前言
開始前先來簡單看看緩存是什么,緩存是一種保存資源副本并在下次請求時(shí)直接使用該副本的技術(shù)。
我們使用 HTTP 緩存,通過復(fù)用緩存資源,減少了客戶端等待時(shí)間和網(wǎng)絡(luò)流量,同時(shí)也能緩解服務(wù)器端的壓力??梢燥@著的提升我們網(wǎng)站和應(yīng)用的性能。雖然 HTTP 緩存不是必須的,但重用緩存的資源通常是必要的,HTTP 緩存是一個(gè) web 性能優(yōu)化的重要手段。
HTTP 緩存的類型
通常 HTTP 緩存策略分為兩種:強(qiáng)緩存和協(xié)商緩存。從字面意思我們可以很直觀的看到它們的差別。強(qiáng)緩存即強(qiáng)制直接使用緩存。協(xié)商緩存就得和服務(wù)器協(xié)商確認(rèn)下這個(gè)緩存能不能用。
強(qiáng)緩存
強(qiáng)緩存不會(huì)向服務(wù)器發(fā)送請求,直接從緩存中讀取資源,在 chrome 控制臺(tái)的 network 選項(xiàng)中可以看到該請求返回 200 的狀態(tài)碼,并且size顯示from disk cache或from memory cache;
協(xié)商緩存
協(xié)商緩存會(huì)先向服務(wù)器發(fā)送一個(gè)請求,服務(wù)器會(huì)根據(jù)這個(gè)請求的 request header 的一些參數(shù)來判斷是否命中協(xié)商緩存,如果命中,則返回 304 狀態(tài)碼并帶上新的 response header 通知瀏覽器從緩存中讀取資源。
HTTP 緩存控制
在 HTTP 中,我們可以通過設(shè)置響應(yīng)頭以及請求頭來控制緩存策略。
強(qiáng)緩存可以通過設(shè)置Expires和Cache-Control 兩種響應(yīng)頭實(shí)現(xiàn)。如果同時(shí)存在,Cache-Control優(yōu)先級高于Expires。
Expires
Expires 響應(yīng)頭,它是 HTTP/1.0 的產(chǎn)物。代表該資源的過期時(shí)間,其值為一個(gè)絕對時(shí)間。它告訴瀏覽器在過期時(shí)間之前可以直接從瀏覽器緩存中存取數(shù)據(jù)。由于是個(gè)絕對時(shí)間,客戶端與服務(wù)端的時(shí)間時(shí)差或誤差等因素可能造成客戶端與服務(wù)端的時(shí)間不一致,將導(dǎo)致緩存命中的誤差。如果在Cache-Control響應(yīng)頭設(shè)置了 max-age 或者 s-max-age 指令,那么 Expires 會(huì)被忽略。
Expires: Wed, 21 Oct 2015 07:28:00 GMT
Cache-Control
Cache-Control 出現(xiàn)于 HTTP/1.1。可以通過指定多個(gè)指令來實(shí)現(xiàn)緩存機(jī)制。主要用表示資源緩存的最大有效時(shí)間。即在該時(shí)間端內(nèi),客戶端不需要向服務(wù)器發(fā)送請求。優(yōu)先級高于 Expires。其過期時(shí)間指令的值是相對時(shí)間,它解決了絕對時(shí)間的帶來的問題。
Cache-Control: max-age=315360000
Cache-Control 有很多屬性,不同的屬性代表的意義也不同。
可緩存性
public表明響應(yīng)可以被任何對象(包括:發(fā)送請求的客戶端,代理服務(wù)器,等等)緩存。private表明響應(yīng)只能被單個(gè)用戶緩存,不能作為共享緩存(即代理服務(wù)器不能緩存它)no-cache不使用強(qiáng)緩存,需要與服務(wù)器進(jìn)行協(xié)商緩存驗(yàn)證。no-store緩存不應(yīng)存儲(chǔ)有關(guān)客戶端請求或服務(wù)器響應(yīng)的任何內(nèi)容,即不使用任何緩存。
過期
max-age=<seconds>緩存存儲(chǔ)的最大周期,超過這個(gè)周期被認(rèn)為過期。s-maxage=<seconds>設(shè)置共享緩存。會(huì)覆蓋max-age和expires,私有緩存會(huì)忽略它max-stale[=<seconds>]客戶端愿意接收一個(gè)已經(jīng)過期的資源,可以設(shè)置一個(gè)可選的秒數(shù),表示響應(yīng)不能已經(jīng)過時(shí)超過該給定的時(shí)間。min-fresh=<seconds>客戶端希望在指定的時(shí)間內(nèi)獲取最新的響應(yīng)
重新驗(yàn)證和重新加載
must-revalidate如頁面過期,則去服務(wù)器進(jìn)行獲取。proxy-revalidate與must-revalidate作用相同,但是用于共享緩存。
其他
only-if-cached不進(jìn)行網(wǎng)絡(luò)請求,完全只使用緩存。no-transform不得對資源進(jìn)行轉(zhuǎn)換和轉(zhuǎn)變。例如,不得對圖像格式進(jìn)行轉(zhuǎn)換。
協(xié)商緩存可以通過 Last-Modified/If-Modified-Since和ETag/If-None-Match這兩對 Header 來控制。
Last-Modified、If-Modified-Since
Last-Modified與If-Modified-Since 的值都是 GMT 格式的時(shí)間字符串,代表的是文件的最后修改時(shí)間。
在服務(wù)器在響應(yīng)請求時(shí),會(huì)通過
Last-Modified告訴瀏覽器資源的最后修改時(shí)間。瀏覽器再次請求服務(wù)器的時(shí)候,請求頭會(huì)包含
Last-Modified字段,后面跟著在緩存中獲得的最后修改時(shí)間。服務(wù)端收到此請求頭發(fā)現(xiàn)有
if-Modified-Since,則與被請求資源的最后修改時(shí)間進(jìn)行對比,如果一致則返回 304 和響應(yīng)報(bào)文頭,瀏覽器只需要從緩存中獲取信息即可。如果已經(jīng)修改,那么開始傳輸響應(yīng)一個(gè)整體,服務(wù)器返回:200 OK
但是在服務(wù)器上經(jīng)常會(huì)出現(xiàn)這種情況,一個(gè)資源被修改了,但其實(shí)際內(nèi)容根本沒發(fā)生改變,會(huì)因?yàn)?code style="font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(228,105,24);background-color:rgb(239,239,239);font-size:.875em;">Last-Modified時(shí)間匹配不上而返回了整個(gè)實(shí)體給客戶端(即使客戶端緩存里有個(gè)一模一樣的資源)。為了解決這個(gè)問題,HTTP/1.1 推出了Etag。Etag 優(yōu)先級高于Last-Modified。
Etag、If-None-Match
Etag都是服務(wù)器為每份資源生成的唯一標(biāo)識(shí),就像一個(gè)指紋,資源變化都會(huì)導(dǎo)致 ETag 變化,跟最后修改時(shí)間沒有關(guān)系,ETag可以保證每一個(gè)資源是唯一的。
在瀏覽器發(fā)起請求,瀏覽器的請求報(bào)文頭會(huì)包含 If-None-Match ?字段,其值為上次返回的Etag發(fā)送給服務(wù)器,服務(wù)器接收到次報(bào)文后發(fā)現(xiàn) If-None-Match 則與被請求資源的唯一標(biāo)識(shí)進(jìn)行對比。如果相同說明資源沒有修改,則響應(yīng)返 304,瀏覽器直接從緩存中獲取數(shù)據(jù)信息。如果不同則說明資源被改動(dòng)過,則響應(yīng)整個(gè)資源內(nèi)容,返回狀態(tài)碼 200。
總結(jié)
通過前文,我們了解到 HTTP 緩存主要分強(qiáng)制緩存和協(xié)商緩存。強(qiáng)制緩存由 Cache-Control,Exipres(HTTP1.0)控制。瀏覽器直接讀本地緩存,不會(huì)再跟服務(wù)器端交互,狀態(tài)碼 200。協(xié)商緩存由 Last-Modified / IfModified-Since, Etag /If-None-Match實(shí)現(xiàn),每次請求需要讓服務(wù)器判斷一下資源是否更新過,從而決定瀏覽器是否使用緩存,如果是,則返回 304,否則重新完整響應(yīng)。
往期精彩回顧:
RESTful API 設(shè)計(jì)最佳實(shí)踐
感謝閱讀,歡迎關(guān)注 ??
左手代碼右手磚,拋磚引玉
給點(diǎn)個(gè)贊,好不好啊
