瀏覽器緩存分為強(qiáng)緩存和協(xié)商緩存:
1)瀏覽器在加載資源時(shí),先根據(jù)這個(gè)資源的一些http header判斷它是否命中強(qiáng)緩存,強(qiáng)緩存如果命中,瀏覽器直接從自己的緩存中讀取資源,不會(huì)發(fā)請(qǐng)求到服務(wù)器。比如某個(gè)css文件,如果瀏覽器在加載它所在的網(wǎng)頁(yè)時(shí),這個(gè)css文件的緩存配置命中了強(qiáng)緩存,瀏覽器就直接從緩存中加載這個(gè)css,連請(qǐng)求都不會(huì)發(fā)送到網(wǎng)頁(yè)所在服務(wù)器;
2)當(dāng)強(qiáng)緩存沒(méi)有命中的時(shí)候,瀏覽器一定會(huì)發(fā)送一個(gè)請(qǐng)求到服務(wù)器,通過(guò)服務(wù)器端依據(jù)資源的另外一些http header驗(yàn)證這個(gè)資源是否命中協(xié)商緩存,如果協(xié)商緩存命中,服務(wù)器會(huì)將這個(gè)請(qǐng)求返回,但是不會(huì)返回這個(gè)資源的數(shù)據(jù),而是告訴客戶(hù)端可以直接從緩存中加載這個(gè)資源,于是瀏覽器就又會(huì)從自己的緩存中去加載這個(gè)資源;
3)強(qiáng)緩存與協(xié)商緩存的共同點(diǎn)是:如果命中,都是從客戶(hù)端緩存中加載資源,而不是從服務(wù)器加載資源數(shù)據(jù);區(qū)別是:強(qiáng)緩存不發(fā)請(qǐng)求到服務(wù)器,協(xié)商緩存會(huì)發(fā)請(qǐng)求到服務(wù)器。
4)當(dāng)協(xié)商緩存也沒(méi)有命中的時(shí)候,瀏覽器直接從服務(wù)器加載資源數(shù)據(jù)。
強(qiáng)緩存原理
強(qiáng)緩存是利用Expires或者Cache-Control這兩個(gè)http response header實(shí)現(xiàn)的,它們都用來(lái)表示資源在客戶(hù)端緩存的有效期。
Expires是http1.0提出的一個(gè)表示資源過(guò)期時(shí)間的header,它描述的是一個(gè)絕對(duì)時(shí)間,由服務(wù)器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,它的緩存原理是:
1)瀏覽器第一次跟服務(wù)器請(qǐng)求一個(gè)資源,服務(wù)器在返回這個(gè)資源的同時(shí),在respone的header加上Expires的header,如:
2)瀏覽器在接收到這個(gè)資源后,會(huì)把這個(gè)資源連同所有response header一起緩存下來(lái)(所以緩存命中的請(qǐng)求返回的header并不是來(lái)自服務(wù)器,而是來(lái)自之前緩存的header);
3)瀏覽器再請(qǐng)求這個(gè)資源時(shí),先從緩存中尋找,找到這個(gè)資源后,拿出它的Expires跟當(dāng)前的請(qǐng)求時(shí)間比較,如果請(qǐng)求時(shí)間在Expires指定的時(shí)間之前,就能命中緩存,否則就不行。
4)如果緩存沒(méi)有命中,瀏覽器直接從服務(wù)器加載資源時(shí),Expires Header在重新加載的時(shí)候會(huì)被更新。
Expires是較老的強(qiáng)緩存管理header,由于它是服務(wù)器返回的一個(gè)絕對(duì)時(shí)間,在服務(wù)器時(shí)間與客戶(hù)端時(shí)間相差較大時(shí),緩存管理容易出現(xiàn)問(wèn)題,比如隨意修改下客戶(hù)端時(shí)間,就能影響緩存命中的結(jié)果。所以在http1.1的時(shí)候,提出了一個(gè)新的header,就是Cache-Control,這是一個(gè)相對(duì)時(shí)間,在配置緩存的時(shí)候,以秒為單位,用數(shù)值表示,如:Cache-Control:max-age=315360000,它的緩存原理是:
1)瀏覽器第一次跟服務(wù)器請(qǐng)求一個(gè)資源,服務(wù)器在返回這個(gè)資源的同時(shí),在respone的header加上Cache-Control的header,如:
2)瀏覽器在接收到這個(gè)資源后,會(huì)把這個(gè)資源連同所有response header一起緩存下來(lái);
3)瀏覽器再請(qǐng)求這個(gè)資源時(shí),先從緩存中尋找,找到這個(gè)資源后,根據(jù)它第一次的請(qǐng)求時(shí)間和Cache-Control設(shè)定的有效期,計(jì)算出一個(gè)資源過(guò)期時(shí)間,再拿這個(gè)過(guò)期時(shí)間跟當(dāng)前的請(qǐng)求時(shí)間比較,如果請(qǐng)求時(shí)間在過(guò)期時(shí)間之前,就能命中緩存,否則就不行。
4)如果緩存沒(méi)有命中,瀏覽器直接從服務(wù)器加載資源時(shí),Cache-Control Header在重新加載的時(shí)候會(huì)被更新。
Cache-Control描述的是一個(gè)相對(duì)時(shí)間,在進(jìn)行緩存命中的時(shí)候,都是利用客戶(hù)端時(shí)間進(jìn)行判斷,所以相比較Expires,Cache-Control的緩存管理更有效,安全一些。
當(dāng)response header中,Expires和Cache-Control同時(shí)存在時(shí),Cache-Control優(yōu)先級(jí)高于Expires
協(xié)商緩存
當(dāng)瀏覽器對(duì)某個(gè)資源的請(qǐng)求沒(méi)有命中強(qiáng)緩存,就會(huì)發(fā)一個(gè)請(qǐng)求到服務(wù)器,驗(yàn)證協(xié)商緩存是否命中,如果協(xié)商緩存命中,請(qǐng)求響應(yīng)返回的http狀態(tài)為304并且會(huì)顯示一個(gè)Not Modified的字符串,比如你打開(kāi)京東的首頁(yè),按f12打開(kāi)開(kāi)發(fā)者工具,再按f5刷新頁(yè)面,查看network,可以看到有不少請(qǐng)求就是命中了協(xié)商緩存的:
查看單個(gè)請(qǐng)求的Response Header,也能看到304的狀態(tài)碼和Not Modified的字符串,只要看到這個(gè)就可說(shuō)明這個(gè)資源是命中了協(xié)商緩存,然后從客戶(hù)端緩存中加載的,而不是服務(wù)器最新的資源:

協(xié)商緩存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】這兩對(duì)Header來(lái)管理的。
【Last-Modified,If-Modified-Since】的控制緩存的原理是:
1)瀏覽器第一次跟服務(wù)器請(qǐng)求一個(gè)資源,服務(wù)器在返回這個(gè)資源的同時(shí),在respone的header加上Last-Modified的header,這個(gè)header表示這個(gè)資源在服務(wù)器上的最后修改時(shí)間:

2)瀏覽器再次跟服務(wù)器請(qǐng)求這個(gè)資源時(shí),在request的header上加上If-Modified-Since的header,這個(gè)header的值就是上一次請(qǐng)求時(shí)返回的Last-Modified的值:

3)服務(wù)器再次收到資源請(qǐng)求時(shí),根據(jù)瀏覽器傳過(guò)來(lái)If-Modified-Since和資源在服務(wù)器上的最后修改時(shí)間判斷資源是否有變化,如果沒(méi)有變化則返回304 Not Modified,但是不會(huì)返回資源內(nèi)容;如果有變化,就正常返回資源內(nèi)容。當(dāng)服務(wù)器返回304 Not Modified的響應(yīng)時(shí),response header中不會(huì)再添加Last-Modified的header,因?yàn)榧热毁Y源沒(méi)有變化,那么Last-Modified也就不會(huì)改變,這是服務(wù)器返回304時(shí)的response header:

4)瀏覽器收到304的響應(yīng)后,就會(huì)從緩存中加載資源。
5)如果協(xié)商緩存沒(méi)有命中,瀏覽器直接從服務(wù)器加載資源時(shí),Last-Modified Header在重新加載的時(shí)候會(huì)被更新,下次請(qǐng)求時(shí),If-Modified-Since會(huì)啟用上次返回的Last-Modified值。
【Last-Modified,If-Modified-Since】都是根據(jù)服務(wù)器時(shí)間返回的header,一般來(lái)說(shuō),在沒(méi)有調(diào)整服務(wù)器時(shí)間和篡改客戶(hù)端緩存的情況下,這兩個(gè)header配合起來(lái)管理協(xié)商緩存是非??煽康模怯袝r(shí)候也會(huì)服務(wù)器上資源其實(shí)有變化,但是最后修改時(shí)間卻沒(méi)有變化的情況,而這種問(wèn)題又很不容易被定位出來(lái),而當(dāng)這種情況出現(xiàn)的時(shí)候,就會(huì)影響協(xié)商緩存的可靠性。所以就有了另外一對(duì)header來(lái)管理協(xié)商緩存,這對(duì)header就是【ETag、If-None-Match】。它們的緩存管理的方式是:
1)瀏覽器第一次跟服務(wù)器請(qǐng)求一個(gè)資源,服務(wù)器在返回這個(gè)資源的同時(shí),在respone的header加上ETag的header,這個(gè)header是服務(wù)器根據(jù)當(dāng)前請(qǐng)求的資源生成的一個(gè)唯一標(biāo)識(shí),這個(gè)唯一標(biāo)識(shí)是一個(gè)字符串,只要資源有變化這個(gè)串就不同,跟最后修改時(shí)間沒(méi)有關(guān)系,所以能很好的補(bǔ)充Last-Modified的問(wèn)題:

2)瀏覽器再次跟服務(wù)器請(qǐng)求這個(gè)資源時(shí),在request的header上加上If-None-Match的header,這個(gè)header的值就是上一次請(qǐng)求時(shí)返回的ETag的值:

3)服務(wù)器再次收到資源請(qǐng)求時(shí),根據(jù)瀏覽器傳過(guò)來(lái)If-None-Match和然后再根據(jù)資源生成一個(gè)新的ETag,如果這兩個(gè)值相同就說(shuō)明資源沒(méi)有變化,否則就是有變化;如果沒(méi)有變化則返回304 Not Modified,但是不會(huì)返回資源內(nèi)容;如果有變化,就正常返回資源內(nèi)容。與Last-Modified不一樣的是,當(dāng)服務(wù)器返回304 Not Modified的響應(yīng)時(shí),由于ETag重新生成過(guò),response header中還會(huì)把這個(gè)ETag返回,即使這個(gè)ETag跟之前的沒(méi)有變化:

4)瀏覽器收到304的響應(yīng)后,就會(huì)從緩存中加載資源。
