淺談瀏覽器 http 緩存機(jī)制

原文:VaJoy Larn(@VaJoy_學(xué)霸模式重啟)

www.cnblogs.com/vajoy/p/5341664.html


針對(duì)瀏覽器的http緩存的分析也算是老生常談了,每隔一段時(shí)間就會(huì)冒出一篇不錯(cuò)的文章,其原理也是各大公司面試時(shí)幾乎必考的問題。


之所以還寫一篇這樣的文章惯豆,是因?yàn)榻诙荚诟阈录夹g(shù)炉擅,想“回歸”下基礎(chǔ)灿椅,也希望盡量總結(jié)的更詳盡些。


那么你是否還需要閱讀本篇文章呢正蛙?可以試著回答下面這個(gè)問題:


我們?cè)谠L問百度首頁的時(shí)候抚太,會(huì)發(fā)現(xiàn)不管怎么刷新頁面塘幅,靜態(tài)資源基本都是返回 200(from cache):



隨便點(diǎn)開一個(gè)靜態(tài)資源是醬的:



哎喲有Response報(bào)頭數(shù)據(jù)呢菇怀,看來服務(wù)器也正常返回了etag什么鬼的應(yīng)有盡有,那狀態(tài)200不是應(yīng)該對(duì)應(yīng)的非緩存狀態(tài)么晌块?要from cache的話不是應(yīng)該返回304才合理么?


難道是度娘的服務(wù)器故障了嗎帅霜?


如果你知道答案匆背,那就可以忽略本文了。


http報(bào)文中與緩存相關(guān)的首部字段


我們先來瞅一眼RFC2616規(guī)定的47種http報(bào)文首部字段中與緩存相關(guān)的字段身冀,事先了解一下能讓咱在心里有個(gè)底:


1. 通用首部字段(就是請(qǐng)求報(bào)文和響應(yīng)報(bào)文都能用上的字段)



2. 請(qǐng)求首部字段



3. 響應(yīng)首部字段



4. 實(shí)體首部字段



后續(xù)大體也會(huì)依次介紹它們钝尸。


場(chǎng)景模擬


為方便模擬各種緩存效果,我們建個(gè)非常簡(jiǎn)單的場(chǎng)景搂根。


1. 頁面文件


我們建個(gè)非常簡(jiǎn)單的html頁面珍促,上面只有一個(gè)本地樣式文件和圖片:


<!DOCTYPE html>

<html>

<head>

<title>緩存測(cè)試</title>

<link?rel="stylesheet"?href="css/reset.css">

</head>

<body>

<h1>哥只是一個(gè)標(biāo)題</h1>

<p><img?src="img/dog.jpg"?/></p>

</body>

</html>


2. 首部字段修改


有時(shí)候一些瀏覽器會(huì)自行給請(qǐng)求首部加上一些字段(如chrome使用F5會(huì)強(qiáng)制加上“cache-control:max-age=0”),會(huì)覆蓋掉一些字段(比如pragma)的功能;另外有時(shí)候我們希望服務(wù)器能多/少返回一些響應(yīng)字段剩愧。


這種情況我們就希望可以手動(dòng)來修改請(qǐng)求或響應(yīng)報(bào)文上的內(nèi)容了猪叙。那么如何實(shí)現(xiàn)呢?這里我們使用Fiddler來完成任務(wù)仁卷。


在Fiddler中我們可以通過“bpu XXX”指令來攔截指定請(qǐng)求穴翩,然后手動(dòng)修改請(qǐng)求內(nèi)容再發(fā)給服務(wù)器、修改響應(yīng)內(nèi)容再發(fā)給客戶端锦积。


以我們的example為例芒帕,頁面文件走nginx通過 http://localhost/ 可直接訪問,所以我們直接執(zhí)行“bpu localhost”攔截所有地址中帶有該字樣的請(qǐng)求:



點(diǎn)擊被攔截的請(qǐng)求丰介,可以在右欄直接修改報(bào)文內(nèi)容(上半?yún)^(qū)域是請(qǐng)求報(bào)文背蟆,下半?yún)^(qū)域是響應(yīng)報(bào)文),點(diǎn)擊黃色的“Break on Response”按鈕可以執(zhí)行下一步(把請(qǐng)求發(fā)給服務(wù)器)哮幢,點(diǎn)擊綠色的按鈕“Run to Completion”可以直接完成整個(gè)請(qǐng)求過程:



通過這個(gè)方法我們可以很輕松地模擬出各種http緩存場(chǎng)景带膀。


3. 瀏覽器的強(qiáng)制策略


如上述,當(dāng)下大多數(shù)瀏覽器在點(diǎn)擊刷新按鈕或按F5時(shí)會(huì)自行加上“Cache-Control:max-age=0”請(qǐng)求字段橙垢,所以我們先約定成俗——后文提及的“刷新”多指的是選中url地址欄并按回車鍵(這樣不會(huì)被強(qiáng)行加上Cache-Control)本砰。


事實(shí)上有的瀏覽器還有一些更奇怪的行為,在后續(xù)我們回答文章開頭問題的時(shí)候會(huì)提到钢悲。


石器時(shí)代的緩存方式


在 http1.0 時(shí)代点额,給客戶端設(shè)定緩存方式可通過兩個(gè)字段——“Pragma”和“Expires”來規(guī)范。雖然這兩個(gè)字段早可拋棄莺琳,但為了做http協(xié)議的向下兼容还棱,你還是可以看到很多網(wǎng)站依舊會(huì)帶上這兩個(gè)字段。


1. Pragma


當(dāng)該字段值為“no-cache”的時(shí)候(事實(shí)上現(xiàn)在RFC中也僅標(biāo)明該可選值)惭等,會(huì)知會(huì)客戶端不要對(duì)該資源讀緩存珍手,即每次都得向服務(wù)器發(fā)一次請(qǐng)求才行。


Pragma屬于通用首部字段,在客戶端上使用時(shí)琳要,常規(guī)要求我們往html上加上這段meta元標(biāo)簽(而且可能還得做些hack放到body后面去):


<meta http-equiv="Pragma" content="no-cache">


它告訴瀏覽器每次請(qǐng)求頁面時(shí)都不要讀緩存寡具,都得往服務(wù)器發(fā)一次請(qǐng)求才行。


BUT!!! 事實(shí)上這種禁用緩存的形式用處很有限:


1. 僅有IE才能識(shí)別這段meta標(biāo)簽含義稚补,其它主流瀏覽器僅能識(shí)別“Cache-Control: no-store”的meta標(biāo)簽(見出處)童叠。

2. 在IE中識(shí)別到該meta標(biāo)簽含義,并不一定會(huì)在請(qǐng)求字段加上Pragma课幕,但的確會(huì)讓當(dāng)前頁面每次都發(fā)新請(qǐng)求(僅限頁面厦坛,頁面上的資源則不受影響)。


做了測(cè)試后發(fā)現(xiàn)也的確如此乍惊,這種客戶端定義Pragma的形式基本沒起到多少作用杜秸。


不過如果是在響應(yīng)報(bào)文上加上該字段就不一樣了:



如上圖紅框部分是再次刷新頁面時(shí)生成的請(qǐng)求,這說明禁用緩存生效润绎,預(yù)計(jì)瀏覽器在收到服務(wù)器的Pragma字段后會(huì)對(duì)資源進(jìn)行標(biāo)記撬碟,禁用其緩存行為,進(jìn)而后續(xù)每次刷新頁面均能重新發(fā)出請(qǐng)求而不走緩存莉撇。


2. Expires


有了Pragma來禁用緩存小作,自然也需要有個(gè)東西來啟用緩存和定義緩存時(shí)間,對(duì)http1.0而言稼钩,Expires就是做這件事的首部字段顾稀。


Expires的值對(duì)應(yīng)一個(gè)GMT(格林尼治時(shí)間),比如“Mon, 22 Jul 2002 11:12:01 GMT”來告訴瀏覽器資源緩存過期時(shí)間坝撑,如果還沒過該時(shí)間點(diǎn)則不發(fā)請(qǐng)求静秆。


在客戶端我們同樣可以使用meta標(biāo)簽來知會(huì)IE(也僅有IE能識(shí)別)頁面(同樣也只對(duì)頁面有效,對(duì)頁面上的資源無效)緩存時(shí)間:


<meta http-equiv="expires" content="mon, 18 apr 2016 14:30:00 GMT">


如果希望在IE下頁面不走緩存巡李,希望每次刷新頁面都能發(fā)新請(qǐng)求抚笔,那么可以把“content”里的值寫為“-1”或“0”。


注意的是該方式僅僅作為知會(huì)IE緩存時(shí)間的標(biāo)記侨拦,你并不能在請(qǐng)求或響應(yīng)報(bào)文中找到Expires字段殊橙。


如果是在服務(wù)端報(bào)頭返回Expires字段,則在任何瀏覽器中都能正確設(shè)置資源緩存的時(shí)間:



在上圖里狱从,緩存時(shí)間設(shè)置為一個(gè)已過期的時(shí)間點(diǎn)(見紅框)膨蛮,則刷新頁面將重新發(fā)送請(qǐng)求(見藍(lán)框)。


那么如果Pragma和Expires一起上陣的話季研,聽誰的敞葛?我們?cè)囈辉嚲椭懒耍?/p>



我們通過Pragma禁用緩存,又給Expires定義一個(gè)還未到期的時(shí)間(紅框)与涡,刷新頁面時(shí)發(fā)現(xiàn)均發(fā)起了新請(qǐng)求(藍(lán)框)惹谐,這意味著Pragma字段的優(yōu)先級(jí)會(huì)更高持偏。


BUT,響應(yīng)報(bào)文中Expires所定義的緩存時(shí)間是相對(duì)服務(wù)器上的時(shí)間而言的氨肌,如果客戶端上的時(shí)間跟服務(wù)器上的時(shí)間不一致(特別是用戶修改了自己電腦的系統(tǒng)時(shí)間)鸿秆,那緩存時(shí)間可能就沒啥意義了。


Cache-Control


針對(duì)上述的“Expires時(shí)間是相對(duì)服務(wù)器而言怎囚,無法保證和客戶端時(shí)間統(tǒng)一”的問題卿叽,http1.1新增了 Cache-Control 來定義緩存過期時(shí)間,若報(bào)文中同時(shí)出現(xiàn)了 Pragma桩了、Expires 和 Cache-Control,會(huì)以 Cache-Control 為準(zhǔn)埠戳。


Cache-Control也是一個(gè)通用首部字段井誉,這意味著它能分別在請(qǐng)求報(bào)文和響應(yīng)報(bào)文中使用。在RFC中規(guī)范了 Cache-Control 的格式為:


"Cache-Control" ":" cache-directive


作為請(qǐng)求首部時(shí)整胃,cache-directive 的可選值有:



作為響應(yīng)首部時(shí)颗圣,cache-directive 的可選值有:



我們依舊可以在HTML頁面加上meta標(biāo)簽來給請(qǐng)求報(bào)頭加上 Cache-Control 字段:


另外 Cache-Control 允許自由組合可選值,例如:


Cache-Control: max-age=3600, must-revalidate


它意味著該資源是從原服務(wù)器上取得的屁使,且其緩存(新鮮度)的有效時(shí)間為一小時(shí)在岂,在后續(xù)一小時(shí)內(nèi),用戶重新訪問該資源則無須發(fā)送請(qǐng)求蛮寂。


當(dāng)然這種組合的方式也會(huì)有些限制蔽午,比如 no-cache 就不能和 max-age、min-fresh酬蹋、max-stale 一起搭配使用及老。


組合的形式還能做一些瀏覽器行為不一致的兼容處理。例如在IE我們可以使用 no-cache 來防止點(diǎn)擊“后退”按鈕時(shí)頁面資源從緩存加載范抓,但在 Firefox 中骄恶,需要使用 no-store 才能防止歷史回退時(shí)瀏覽器不從緩存中去讀取數(shù)據(jù),故我們?cè)陧憫?yīng)報(bào)頭加上如下組合值即可做兼容處理:


Cache-Control: no-cache, no-store


緩存校驗(yàn)字段


上述的首部字段均能讓客戶端決定是否向服務(wù)器發(fā)送請(qǐng)求匕垫,比如設(shè)置的緩存時(shí)間未過期僧鲁,那么自然直接從本地緩存取數(shù)據(jù)即可(在chrome下表現(xiàn)為200 from cache),若緩存時(shí)間過期了或資源不該直接走緩存象泵,則會(huì)發(fā)請(qǐng)求到服務(wù)器去寞秃。


我們現(xiàn)在要說的問題是,如果客戶端向服務(wù)器發(fā)了請(qǐng)求偶惠,那么是否意味著一定要讀取回該資源的整個(gè)實(shí)體內(nèi)容呢蜕该?


我們?cè)囍@么想——客戶端上某個(gè)資源保存的緩存時(shí)間過期了氧枣,但這時(shí)候其實(shí)服務(wù)器并沒有更新過這個(gè)資源脖卖,如果這個(gè)資源數(shù)據(jù)量很大弟晚,客戶端要求服務(wù)器再把這個(gè)東西重新發(fā)一遍過來,是否非常浪費(fèi)帶寬和時(shí)間呢烦味?


答案是肯定的,那么是否有辦法讓服務(wù)器知道客戶端現(xiàn)在存有的緩存文件待侵,其實(shí)跟自己所有的文件是一致的胶滋,然后直接告訴客戶端說“這東西你直接用緩存里的就可以了,我這邊沒更新過呢皆的,就不再傳一次過去了”覆履。


為了讓客戶端與服務(wù)器之間能實(shí)現(xiàn)緩存文件是否更新的驗(yàn)證、提升緩存的復(fù)用率费薄,Http1.1新增了幾個(gè)首部字段來做這件事情硝全。


1. Last-Modified


服務(wù)器將資源傳遞給客戶端時(shí),會(huì)將資源最后更改的時(shí)間以“Last-Modified: GMT”的形式加在實(shí)體首部上一起返回給客戶端楞抡。


客戶端會(huì)為資源標(biāo)記上該信息伟众,下次再次請(qǐng)求時(shí),會(huì)把該信息附帶在請(qǐng)求報(bào)文中一并帶給服務(wù)器去做檢查召廷,若傳遞的時(shí)間值與服務(wù)器上該資源最終修改時(shí)間是一致的凳厢,則說明該資源沒有被修改過,直接返回304狀態(tài)碼即可竞慢。


至于傳遞標(biāo)記起來的最終修改時(shí)間的請(qǐng)求報(bào)文首部字段一共有兩個(gè):


⑴ If-Modified-Since: Last-Modified-value


示例為 ?If-Modified-Since: Thu, 31 Mar 2016 07:07:52 GMT


該請(qǐng)求首部告訴服務(wù)器如果客戶端傳來的最后修改時(shí)間與服務(wù)器上的一致先紫,則直接回送304 和響應(yīng)報(bào)頭即可。


當(dāng)前各瀏覽器均是使用的該請(qǐng)求首部來向服務(wù)器傳遞保存的 Last-Modified 值筹煮。


⑵ If-Unmodified-Since: Last-Modified-value


告訴服務(wù)器遮精,若Last-Modified沒有匹配上(資源在服務(wù)端的最后更新時(shí)間改變了),則應(yīng)當(dāng)返回412(Precondition Failed) 狀態(tài)碼給客戶端败潦。


當(dāng)遇到下面情況時(shí)仑鸥,If-Unmodified-Since 字段會(huì)被忽略:


1. Last-Modified值對(duì)上了(資源在服務(wù)端沒有新的修改);

2. 服務(wù)端需返回2XX和412之外的狀態(tài)碼变屁;

3. 傳來的指定日期不合法


Last-Modified 說好卻也不是特別好眼俊,因?yàn)槿绻诜?wù)器上,一個(gè)資源被修改了粟关,但其實(shí)際內(nèi)容根本沒發(fā)生改變疮胖,會(huì)因?yàn)長ast-Modified時(shí)間匹配不上而返回了整個(gè)實(shí)體給客戶端(即使客戶端緩存里有個(gè)一模一樣的資源)。


2. ETag


為了解決上述Last-Modified可能存在的不準(zhǔn)確的問題闷板,Http1.1還推出了 ETag 實(shí)體首部字段澎灸。


服務(wù)器會(huì)通過某種算法,給資源計(jì)算得出一個(gè)唯一標(biāo)志符(比如md5標(biāo)志)遮晚,在把資源響應(yīng)給客戶端的時(shí)候性昭,會(huì)在實(shí)體首部加上“ETag: 唯一標(biāo)識(shí)符”一起返回給客戶端。


客戶端會(huì)保留該 ETag 字段县遣,并在下一次請(qǐng)求時(shí)將其一并帶過去給服務(wù)器糜颠。服務(wù)器只需要比較客戶端傳來的ETag跟自己服務(wù)器上該資源的ETag是否一致汹族,就能很好地判斷資源相對(duì)客戶端而言是否被修改過了。


如果服務(wù)器發(fā)現(xiàn)ETag匹配不上其兴,那么直接以常規(guī)GET 200回包形式將新的資源(當(dāng)然也包括了新的ETag)發(fā)給客戶端顶瞒;如果ETag是一致的,則直接返回304知會(huì)客戶端直接使用本地緩存即可元旬。


那么客戶端是如何把標(biāo)記在資源上的 ETag 傳去給服務(wù)器的呢榴徐?請(qǐng)求報(bào)文中有兩個(gè)首部字段可以帶上 ETag 值:


⑴ If-None-Match: ETag-value


示例為 ?If-None-Match: "56fcccc8-1699"


告訴服務(wù)端如果 ETag 沒匹配上需要重發(fā)資源數(shù)據(jù),否則直接回送304 和響應(yīng)報(bào)頭即可匀归。


當(dāng)前各瀏覽器均是使用的該請(qǐng)求首部來向服務(wù)器傳遞保存的 ETag 值坑资。


⑵ If-Match: ETag-value


告訴服務(wù)器如果沒有匹配到ETag,或者收到了“*”值而當(dāng)前并沒有該資源實(shí)體穆端,則應(yīng)當(dāng)返回412(Precondition Failed) 狀態(tài)碼給客戶端袱贮。否則服務(wù)器直接忽略該字段。


If-Match 的一個(gè)應(yīng)用場(chǎng)景是徙赢,客戶端走PUT方法向服務(wù)端請(qǐng)求上傳/更替資源字柠,這時(shí)候可以通過 If-Match 傳遞資源的ETag探越。


需要注意的是狡赐,如果資源是走分布式服務(wù)器(比如CDN)存儲(chǔ)的情況,需要這些服務(wù)器上計(jì)算ETag唯一值的算法保持一致钦幔,才不會(huì)導(dǎo)致明明同一個(gè)文件枕屉,在服務(wù)器A和服務(wù)器B上生成的ETag卻不一樣。


如果 Last-Modified 和 ETag 同時(shí)被使用鲤氢,則要求它們的驗(yàn)證都必須通過才會(huì)返回304搀擂,若其中某個(gè)驗(yàn)證沒通過,則服務(wù)器會(huì)按常規(guī)返回資源實(shí)體及200狀態(tài)碼卷玉。


在較新的 nginx 上默認(rèn)是同時(shí)開啟了這兩個(gè)功能的:



上圖的前三條請(qǐng)求是原始請(qǐng)求哨颂,接著的三條請(qǐng)求是刷新頁面后的新請(qǐng)求,在發(fā)新請(qǐng)求之前我們修改了 reset.css 文件相种,所以它的 Last-Modified 和 ETag 均發(fā)生了改變威恼,服務(wù)器因此返回了新的文件給客戶端(狀態(tài)值為200)。


而 dog.jpg 我們沒有做修改寝并,其Last-Modified 和 ETag在服務(wù)端是保持不變的箫措,故服務(wù)器直接返回了304狀態(tài)碼讓客戶端直接使用緩存的 dog.jpg 即可,沒有把實(shí)體內(nèi)容返回給客戶端(因?yàn)闆]必要)衬潦。


緩存實(shí)踐


當(dāng)我們?cè)谝粋€(gè)項(xiàng)目上做http緩存的應(yīng)用時(shí)斤蔓,我們還是會(huì)把上述提及的大多數(shù)首部字段均使用上,例如使用 Expires 來兼容舊的瀏覽器镀岛,使用 Cache-Control 來更精準(zhǔn)地利用緩存弦牡,然后開啟 ETag 跟 Last-Modified 功能進(jìn)一步復(fù)用緩存減少流量友驮。


那么這里會(huì)有一個(gè)小問題——Expires 和 Cache-Control 的值應(yīng)設(shè)置為多少合適呢?


答案是不會(huì)有過于精準(zhǔn)的值喇伯,均需要進(jìn)行按需評(píng)估喊儡。


例如頁面鏈接的請(qǐng)求常規(guī)是無須做長時(shí)間緩存的,從而保證回退到頁面時(shí)能重新發(fā)出請(qǐng)求稻据,百度首頁是用的 Cache-Control:private艾猜,騰訊首頁則是設(shè)定了60秒的緩存,即 Cache-Control:max-age=60捻悯。


而靜態(tài)資源部分匆赃,特別是圖片資源,通常會(huì)設(shè)定一個(gè)較長的緩存時(shí)間今缚,而且這個(gè)時(shí)間最好是可以在客戶端靈活修改的算柳。以騰訊的某張圖片為例:


http://i.gtimg.cn/vipstyle/vipportal/v4/img/common/logo.png?max_age=2592000


客戶端可以通過給圖片加上“max_age”的參數(shù)來定義服務(wù)器返回的緩存時(shí)間:



當(dāng)然這需要有一個(gè)前提——靜態(tài)資源能確保長時(shí)間不做改動(dòng)。如果一個(gè)腳本文件響應(yīng)給客戶端并做了長時(shí)間的緩存姓言,而服務(wù)端在近期修改了該文件的話瞬项,緩存了此腳本的客戶端將無法及時(shí)獲得新的數(shù)據(jù)。


解決該困擾的辦法也簡(jiǎn)單——把服務(wù)側(cè)ETag的那一套也搬到前端來用——頁面的靜態(tài)資源以版本形式發(fā)布何荚,常用的方法是在文件名或參數(shù)帶上一串md5或時(shí)間標(biāo)記符:


https://#/hm.js?e23800c454aa573c0ccb16b52665ac26

http://tb1.bdstatic.com/tb/_/tbean_safe_ajax_94e7ca2.js

http://img1.gtimg.com/ninja/2/2016/04/ninja145972803357449.jpg


如果文件被修改了囱淋,才更改其標(biāo)記符內(nèi)容,這樣能確辈吞粒客戶端能及時(shí)從服務(wù)器收取到新修改的文件妥衣。


關(guān)于開頭的問題


現(xiàn)在回過頭來看文章開頭的問題,可能會(huì)覺得答案很容易回答出來戒傻。


百度首頁的資源在刷新后實(shí)際沒有發(fā)送任何請(qǐng)求税手,因?yàn)?Cache-Control 定義的緩存時(shí)間段還沒到期。在Chrome中即使沒發(fā)送請(qǐng)求需纳,但只要從本地的緩存中取芦倒,都會(huì)在Network面板顯示一條狀態(tài)為200且注明“from cache”的偽請(qǐng)求,其Response內(nèi)容只是上一次回包留下的數(shù)據(jù)不翩。


然而這并不是問題的全部答案兵扬,我們前面提到過,在Chrome中如果點(diǎn)擊“刷新”按鈕慌盯,Chrome會(huì)強(qiáng)制給所有資源加上“Cache-Control: max-age=0”的請(qǐng)求首部并向服務(wù)器發(fā)送驗(yàn)證請(qǐng)求的周霉,而在文章開頭的動(dòng)圖中,我們的確點(diǎn)擊了“刷新”按鈕亚皂,卻不見瀏覽器發(fā)去新請(qǐng)求(并返回304)俱箱。


關(guān)于這個(gè)問題其實(shí)在組內(nèi)跟小伙伴們討論過,通過Fiddler抓包發(fā)現(xiàn)灭必,如果關(guān)閉Chrome的開發(fā)者面板再點(diǎn)擊“刷新”按鈕狞谱,瀏覽器是會(huì)按預(yù)期發(fā)送驗(yàn)證請(qǐng)求且接收返回的304響應(yīng)的乃摹,另外這個(gè)奇怪的情況在不同的網(wǎng)站甚至不同的電腦下出現(xiàn)頻率都不一致,所以暫時(shí)將其歸咎于瀏覽器的怪異反應(yīng)跟衅。


那么有這么一個(gè)問題——是否有辦法在瀏覽器點(diǎn)擊“刷新”按鈕的時(shí)候不讓瀏覽器去發(fā)新的驗(yàn)證請(qǐng)求呢孵睬?


辦法還是有的,就是不怎么實(shí)用——在頁面加載完畢后通過腳本動(dòng)態(tài)地添加資源:


$(window).load(function()?{

??????var?bg='http://img.infinitynewtab.com/wallpaper/100.jpg';

??????setTimeout(function()?{??//setTimeout是必須的

???????$('#bgOut').css('background-image',?'url('+bg+')');

??????},0);

});


出處來自知乎伶跷,更具體的解釋可以去看看掰读。


其它相關(guān)的首部字段


事實(shí)上較常用和重要的緩存相關(guān)字段我們都介紹完了,這里順帶講講幾個(gè)跟緩存有關(guān)系叭莫,但沒那么主要的響應(yīng)首部字段蹈集。


1. Vary


“vary”本身是“變化”的意思,而在http報(bào)文中更趨于是“vary from”(與雇初。拢肆。。不同)的含義靖诗,它表示服務(wù)端會(huì)以什么基準(zhǔn)字段來區(qū)分郭怪、篩選緩存版本。


我們先考慮這么一個(gè)問題——在服務(wù)端有著這么一個(gè)地址刊橘,如果是IE用戶則返回針對(duì)IE開發(fā)的內(nèi)容鄙才,否則返回另一個(gè)主流瀏覽器版本的內(nèi)容。這很簡(jiǎn)單伤为,服務(wù)端獲取到請(qǐng)求的 User-Agent 字段做處理即可咒循。但是用戶請(qǐng)求的是代理服務(wù)器而非原服務(wù)器据途,且代理服務(wù)器如果直接把緩存的IE版本資源發(fā)給了非IE的客戶端绞愚,這就出問題了。


因此 Vary 便是著手處理該問題的首部字段颖医,我們可以在響應(yīng)報(bào)文加上:


Vary: User-Agent


便能知會(huì)代理服務(wù)器需要以 User-Agent 這個(gè)請(qǐng)求首部字段來區(qū)別緩存版本位衩,防止傳遞給客戶端的緩存不正確。


Vary 也接受條件組合的形式:


Vary: User-Agent, Accept-Encoding


這意味著服務(wù)器應(yīng)以 User-Agent 和 Accept-Encoding 兩個(gè)請(qǐng)求首部字段來區(qū)分緩存版本熔萧。


2. Date 和 Age


HTTP并沒有提供某種方法來幫用戶區(qū)分其收到的資源是否命中了代理服務(wù)器的緩存糖驴,但在客戶端我們可以通過計(jì)算響應(yīng)報(bào)文中的 Date 和 Age 字段來得到答案。


Date 理所當(dāng)然是原服務(wù)器發(fā)送該資源響應(yīng)報(bào)文的時(shí)間(GMT格式)佛致,如果你發(fā)現(xiàn) Date 的時(shí)間與“當(dāng)前時(shí)間”差別較大贮缕,或者連續(xù)F5刷新發(fā)現(xiàn) Date 的值都沒變化,則說明你當(dāng)前請(qǐng)求是命中了代理服務(wù)器的緩存俺榆。


上述的“當(dāng)前時(shí)間”自然是相對(duì)于原服務(wù)器而言的時(shí)間感昼,那么如何獲悉原服務(wù)器的當(dāng)前時(shí)間呢?


常規(guī)從頁面地址請(qǐng)求的響應(yīng)報(bào)文中可獲得罐脊,以博客園首頁為例:



每次你刷新頁面定嗓,瀏覽器都會(huì)重新發(fā)出這條url的請(qǐng)求蜕琴,你會(huì)發(fā)現(xiàn)其 Date 值是不斷變化的,這說明該鏈接沒有命中緩存宵溅,都是從原服務(wù)器返回過來的數(shù)據(jù)凌简。


因此我們可以拿頁面上其它靜態(tài)資源請(qǐng)求回包中的 Date 與其進(jìn)行對(duì)比,若靜態(tài)資源的 Date 早于原服務(wù)端時(shí)間恃逻,則說明命中了代理服務(wù)器緩存雏搂。


通常還滿足這么個(gè)條件:


靜態(tài)資源Age + 靜態(tài)資源Date = 原服務(wù)端Date


這里的 Age 也是響應(yīng)報(bào)文中的首部字段,它表示該文件在代理服務(wù)器中存在的時(shí)間(秒)寇损,如文件被修改或替換畔派,Age會(huì)重新由0開始累計(jì)。


我們?cè)谏厦婺菑埐┛蛨@首頁報(bào)文截圖的同個(gè)場(chǎng)景下润绵,看看某個(gè)文件(jQuery.js)命中代理服務(wù)器緩存的回包數(shù)據(jù):



會(huì)發(fā)現(xiàn)它滿足我們上述的規(guī)則:


//return true

new?Date('Mon, 04 Apr 2016 07:03:17 GMT')/1000?==?new?Date('Sat, 19 Dec 2015 01:29:14 GMT')/1000?+?9264843


不過這條規(guī)則也不一定準(zhǔn)確线椰,特別是當(dāng)原服務(wù)器經(jīng)常修改系統(tǒng)時(shí)間的情況下。


關(guān)于http緩存原理的知識(shí)就整理到這尘盼,希望能讓你有所收獲憨愉,共勉~

感興趣的小伙伴,可以關(guān)注公眾號(hào)【grain先森】卿捎,回復(fù)關(guān)鍵詞 “vue”配紫,獲取更多資料,更多關(guān)鍵詞玩法期待你的探索~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末午阵,一起剝皮案震驚了整個(gè)濱河市躺孝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌底桂,老刑警劉巖植袍,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異籽懦,居然都是意外死亡于个,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門暮顺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來厅篓,“玉大人,你說我怎么就攤上這事捶码∮鸬” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵惫恼,是天一觀的道長档押。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么汇荐? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任洞就,我火速辦了婚禮,結(jié)果婚禮上掀淘,老公的妹妹穿的比我還像新娘旬蟋。我一直安慰自己,他們只是感情好革娄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布倾贰。 她就那樣靜靜地躺著,像睡著了一般拦惋。 火紅的嫁衣襯著肌膚如雪匆浙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天厕妖,我揣著相機(jī)與錄音首尼,去河邊找鬼。 笑死言秸,一個(gè)胖子當(dāng)著我的面吹牛软能,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播举畸,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼查排,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了抄沮?” 一聲冷哼從身側(cè)響起跋核,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叛买,沒想到半個(gè)月后砂代,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡聪全,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年泊藕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辅辩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片难礼。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖玫锋,靈堂內(nèi)的尸體忽然破棺而出蛾茉,到底是詐尸還是另有隱情,我是刑警寧澤撩鹿,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布谦炬,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏键思。R本人自食惡果不足惜础爬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望吼鳞。 院中可真熱鬧看蚜,春花似錦、人聲如沸赔桌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疾党。三九已至音诫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間雪位,已是汗流浹背竭钝。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雹洗,地道東北人蜓氨。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像队伟,于是被迫代替她去往敵國和親穴吹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容