【轉(zhuǎn)載請注明出處】:https://blog.csdn.net/huahao1989/article/details/107730210
整個 Web 系統(tǒng)架構(gòu)在HTTP 協(xié)議之上, 利用 HTTP 的緩存機制不僅可以極大地減少服務(wù)器負載矗积, 更重要的是加速頁面的載入全肮,以及減少用戶的流量消耗。 快速到達和易于訪問是 Web 與生俱來的特性棘捣, 其緩存機制也早已被服務(wù)器和瀏覽器廠商廣泛地實現(xiàn), 我們作為 Web 內(nèi)容的作者何樂而不為呢休建?
HTTP 緩存簡介
談起 HTTP 緩存你首先想到的一定是磁盤緩存乍恐,以及 304 狀態(tài)碼。 這是瀏覽器處理緩存的兩種情況:
- 瀏覽器詢問服務(wù)器緩存是否有效测砂,服務(wù)器返回 304 指示瀏覽器使用緩存茵烈。
- 資源仍然處于有效期時,瀏覽器會直接使用磁盤緩存(在刷新時稍有不同)砌些。
每個狀態(tài)的詳細說明如下:
1呜投、Cache-Control
Cache-Control
在 HTTP 響應(yīng)頭中,用于指示代理和 UA 使用何種緩存策略存璃。比如:
- no-cache為本次響應(yīng)不可直接用于后續(xù)請求(在沒有向服務(wù)器進行校驗的情況下)
- no-store為禁止緩存(不得存儲到非易失性介質(zhì)仑荐,如果有的話盡量移除,用于敏感信息)
-
private
為僅 UA 可緩存 -
public
為大家都可以緩存纵东。
當(dāng)Cache-Control
為可緩存時粘招,同時可指定緩存時間(比如public, max-age:86400
)。 這意味著在 1 天(60x60x24=86400)時間內(nèi)偎球,瀏覽器都可以直接使用該緩存洒扎。 當(dāng)然瀏覽器也有權(quán)隨時丟棄任何一項緩存,因此這里可能有一致性問題衰絮。
2袍冷、Etag
如果資源本身確實會隨時發(fā)生改動,還用 Cache-Control 就會使用戶看到的頁面得不到更新猫牡。 但如果還希望利用 HTTP 緩存胡诗,這就需要有條件的(conditional)HTTP 請求。
HTTP協(xié)議規(guī)格說明定義ETag為“被請求變量的實體標(biāo)記”镊掖,弱實體只要內(nèi)容語義沒變即可乃戈,強實體指字節(jié)必須完全一致,建議使用弱實體亩进。
如果響應(yīng)體包含Etag字段症虑,則瀏覽器在下次發(fā)送請求時會帶 If-None-Match 頭字段, 來詢問服務(wù)器該版本是否仍然可用归薛。如果服務(wù)器發(fā)現(xiàn)該版本仍然是最新的谍憔, 就可以返回 304 狀態(tài)碼指示 UA 繼續(xù)使用緩存匪蝙。
類似服務(wù)器端返回的格式:
ETag: W/"3ae83efccfc543bad6866e325cd8bfb9"
客戶端的查詢更新格式是這樣的:
If-None-Match:W/"3ae83efccfc543bad6866e325cd8bfb9"
如果ETag沒改變,則返回狀態(tài)304习贫。
3逛球、Last-Modified
在瀏覽器第一次請求某一個URL時,服務(wù)器端的返回狀態(tài)會是200苫昌,內(nèi)容是請求的資源颤绕,同時有一個Last-Modified的屬性標(biāo)記(HttpReponse Header)此文件在服務(wù)期端最后被修改的時間,格式類似這樣:
Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT
客戶端第二次請求此URL時祟身,根據(jù)HTTP協(xié)議的規(guī)定奥务,瀏覽器會向服務(wù)器傳送If-Modified-Since報頭(HttpRequest Header),詢問該時間之后文件是否有被修改過:
If-Modified-Since:Tue, 24 Feb 2009 08:01:04 GMT
如果服務(wù)器端的資源沒有變化袜硫,則自動返回HTTP 304(NotChanged)狀態(tài)碼氯葬,內(nèi)容為空,這樣就節(jié)省了傳輸數(shù)據(jù)量婉陷。當(dāng)服務(wù)器端代碼發(fā)生改變或者重啟服務(wù)器時帚称,則重新發(fā)出資源,返回和第一次請求時類似秽澳。從而保證不向客戶端重復(fù)發(fā)出資源闯睹,也保證當(dāng)服務(wù)器有變化時,客戶端能夠得到最新的資源肝集。
注:如果If-Modified-Since的時間比服務(wù)器當(dāng)前時間(當(dāng)前的請求時間request_time)還晚瞻坝,會認為是個非法請求
4、Expires
給出的日期/時間后杏瞻,被響應(yīng)認為是過時所刀。如Expires:Thu, 02 Apr 2009 05:14:08 GMT
需和Last-Modified結(jié)合使用。用于控制請求文件的有效時間捞挥,當(dāng)請求數(shù)據(jù)在有效期內(nèi)時客戶端瀏覽器從緩存請求數(shù)據(jù)而不是服務(wù)器端浮创。當(dāng)緩存中數(shù)據(jù)失效或過期,才決定從服務(wù)器更新數(shù)據(jù)砌函。
5斩披、Last-Modified和Expires
Last-Modified標(biāo)識能夠節(jié)省一點帶寬,但是還是逃不掉發(fā)一個HTTP請求出去讹俊,而且要和Expires一起用垦沉。而Expires標(biāo)識卻使得瀏覽器干脆連HTTP請求都不用發(fā),比如當(dāng)用戶F5或者點擊Refresh按鈕的時候就算對于有Expires的URI仍劈,一樣也會發(fā)一個HTTP請求出去厕倍,所以,Last-Modified還是要用的贩疙,而且要和Expires一起用讹弯。
6况既、Etag和Expires
如果服務(wù)器端同時設(shè)置了Etag和Expires時,Etag原理同樣组民,即與Last-Modified/Etag對應(yīng)的HttpRequestHeader:If-Modified-Since和If-None-Match棒仍。我們可以看到這兩個Header的值和WebServer發(fā)出的Last-Modified, Etag值完全一樣;在完全匹配If-Modified-Since和If-None-Match即檢查完修改時間和Etag之后臭胜,服務(wù)器才能返回304.
7莫其、Last-Modified和Etag
分布式系統(tǒng)里多臺機器間文件的last-modified必須保持一致,以免負載均衡到不同機器導(dǎo)致比對失敗
分布式系統(tǒng)盡量關(guān)閉掉Etag(每臺機器生成的etag都會不一樣)
Last-Modified和ETags請求的http報頭一起使用耸三,服務(wù)器首先產(chǎn)生Last-Modified/Etag標(biāo)記榜配,服務(wù)器可在稍后使用它來判斷頁面是否已經(jīng)被修改,來決定文件是否繼續(xù)緩存
過程如下:
- 客戶端請求一個頁面(A)吕晌。
- 服務(wù)器返回頁面A,并在給A加上一個Last-Modified/ETag临燃。
- 客戶端展現(xiàn)該頁面睛驳,并將頁面連同Last-Modified/ETag一起緩存。
- 客戶再次請求頁面A膜廊,并將上次請求時服務(wù)器返回的Last-Modified/ETag一起傳遞給服務(wù)器乏沸。
- 服務(wù)器檢查該Last-Modified或ETag,并判斷出該頁面自上次客戶端請求之后還未被修改爪瓜,直接返回響應(yīng)304和一個空的響應(yīng)體蹬跃。
注:
- Last-Modified和Etag頭都是由WebServer發(fā)出的HttpReponse Header,WebServer應(yīng)該同時支持這兩種頭铆铆。
- WebServer發(fā)送完Last-Modified/Etag頭給客戶端后蝶缀,客戶端會緩存這些頭;
- 客戶端再次發(fā)起相同頁面的請求時薄货,將分別發(fā)送與Last-Modified/Etag對應(yīng)的HttpRequestHeader:If-Modified-Since和If-None-Match翁都。這兩個Header的值和WebServer發(fā)出的Last-Modified,Etag值完全一樣;
- 通過上述值到服務(wù)器端檢查谅猾,判斷文件是否繼續(xù)緩存柄慰;
8、關(guān)于 Cache-Control: max-age=秒 和 Expires
Expires = 時間税娜,HTTP 1.0 版本坐搔,緩存的載止時間,允許客戶端在這個時間之前不去檢查(發(fā)請求)
max-age = 秒敬矩,HTTP 1.1版本概行,資源在本地緩存多少秒。
如果max-age和Expires同時存在谤绳,則被Cache-Control的max-age覆蓋占锯。
Expires 的一個缺點就是袒哥,返回的到期時間是服務(wù)器端的時間,這樣存在一個問題消略,如果客戶端的時間與服務(wù)器的時間相差很大堡称,那么誤差就很大,所以在HTTP 1.1版開始艺演,使用Cache-Control: max-age=秒替代却紧。
Expires =max-age + “每次下載時的當(dāng)前的request時間”
所以一旦重新下載的頁面后,expires就重新計算一次胎撤,但last-modified不會變化
9晓殊、瀏覽器刷新
正常重新加載
按下刷新按鈕或快捷鍵(在 MacOS 中是 Cmd+R)會觸發(fā)瀏覽器的“正常重新加載”(normal reload), 此時瀏覽器會執(zhí)行一次 Conditional GET伤提。 Cache-Control
等緩存頭字段會被忽略巫俺,并且?guī)?code>If-None-Match, If-Modified-Since
等頭字段。 此時服務(wù)器總會收到一次 HTTP GET 請求肿男。 在 Chrome 中按下刷新介汹,瀏覽器還會帶如下請求頭:
Cache-Control:max-age=0
注意:在地址欄重新輸入當(dāng)前頁面地址并按下回車也會當(dāng)做刷新處理, 這意味著只有從新標(biāo)簽頁或超鏈接打開時舶沛,才能觀察到直接使用硬盤緩存的情況嘹承。
強制重新加載
在 Chrome 中按下 Cmd+Shift+R (MacOS)可以觸發(fā)強制重新加載(Hard Reload), 此時包括頁面本身在內(nèi)的所有資源都不會使用緩存如庭。 瀏覽器直接發(fā)送 HTTP 請求且不帶任何條件請求字段叹卷。 在 Chrome 中強制刷新,瀏覽器還會帶如下請求頭:
Cache-Control: no-cache
Pragma: no-cache
如何讓緩存的靜態(tài)文件失效
一般我們在頁面上引用很多js或者css文件坪它,一旦請求過并且緩存在瀏覽器中的資源并沒有失效骤竹,這個時候發(fā)現(xiàn)我們有個bug需要修改或者有新的東西需要發(fā)布,你要怎么辦哟楷?有些人就說了瘤载,強制刷新下瀏覽器就好了,或者在請求的時候不返回304卖擅,直接返回新的資源內(nèi)容鸣奔,但是這樣并不好操作,一是用戶未必知道強制刷新或者清理緩存惩阶,二是我們只想在發(fā)布新的內(nèi)容之后第一次用戶的請求返回新的內(nèi)容并緩存挎狸,后面還是走緩存;三是我們一般都會使用CDN断楷,每次發(fā)布完之后還需要清理CDN緩存锨匆,很是麻煩。其實有一個最簡單的辦法就是在引用這些靜態(tài)資源的時候加一個版本號即可,類似.../js/index.js?v=1.0
這樣的恐锣,如果修改了內(nèi)容茅主,那么只需要改一下版本號即可,瀏覽器自然會獲取到新的內(nèi)容土榴。
歡迎關(guān)注 “后端老鳥” 公眾號诀姚,接下來會發(fā)一系列的專題文章,包括Java玷禽、Python赫段、Linux、SpringBoot矢赁、SpringCloud糯笙、Dubbo、算法撩银、技術(shù)團隊的管理等给涕,還有各種腦圖和學(xué)習(xí)資料,NFC技術(shù)额获、搜索技術(shù)稠炬、爬蟲技術(shù)、推薦技術(shù)咪啡、音視頻互動直播等,只要有時間我就會整理分享暮屡,敬請期待撤摸,現(xiàn)成的筆記、腦圖和學(xué)習(xí)資料如果大家有需求也可以公眾號留言提前獲取褒纲。由于本人在所有團隊中基本都處于攻堅和探路的角色准夷,搞過的東西多,遇到的坑多莺掠,解決的問題也很多衫嵌,歡迎大家加公眾號進群一起交流學(xué)習(xí)。
【轉(zhuǎn)載請注明出處】:https://blog.csdn.net/huahao1989/article/details/107730210