你了解過瀏覽器緩存機制嗎?
相信很多前端童鞋對于瀏覽器緩存都不太陌生,但是如果沒有系統(tǒng)的歸納總結(jié),可能三言兩句很難說明白。如何才能完美的回答,這是一個值得思考的問題。
當(dāng)然,我們不能為了應(yīng)對面試才去掌握,而應(yīng)該當(dāng)作技能儲備起來,做到活學(xué)活用。
一、為什么要緩存
1.緩存可以減少用戶等待時間,提升用戶體驗;
2.減少網(wǎng)絡(luò)帶寬消耗
對于網(wǎng)站運營者和用戶,帶寬都代表著成本,過多的帶寬消耗,都需要支付額外的費用。如果可以使用緩存,只會產(chǎn)生極小的網(wǎng)絡(luò)流量,這將有效的降低運營成本。
3.降低服務(wù)器壓力
給網(wǎng)絡(luò)資源設(shè)定有效期之后,用戶可以重復(fù)使用本地的緩存,減少對源服務(wù)器的請求,降低服務(wù)器的壓力。此外,搜索引擎的爬蟲機器人也能根據(jù)過期機制降低爬取的頻率,也能有效降低服務(wù)器的壓力。
需要注意:緩存使用不當(dāng),會有「臟數(shù)據(jù)」,導(dǎo)致用戶數(shù)據(jù)異常。
二、常見緩存類型
瀏覽器緩存分為強緩存和協(xié)商緩存。
強緩存
1.Expires:GMT 格式的時間字符串,代表緩存資源的過期時間
Expires 也是需要在服務(wù)端配置(具體配置也根據(jù)服務(wù)器而定),Expires 添加的是該資源過期的日期。瀏覽器會根據(jù)該過期日期與客戶端時間對比,如果過期時間還沒到,則會去緩存中讀取該資源,如果已經(jīng)到期了,則瀏覽器判斷為該資源已經(jīng)不新鮮要重新從服務(wù)端獲取。
通過這種方式,可以實現(xiàn)直接從瀏覽器緩存中讀取,而不需要去服務(wù)端判斷是否已經(jīng)緩存,避免了這次 HTTP 請求。值得注意的是 Expires 時間可能存在 客戶端時間跟服務(wù)端時間不一致 的問題。
建議 Expires 結(jié)合 Cache-Control 一起使用,大型網(wǎng)站中一起使用的情況比較多見。
2.Cache-Control: max-age 強緩存利用其 max-age 值來判斷緩存資源的最大生命周期,它的值單位為秒。
Cache-Control 屬性值是在 server 端配置的,不同的服務(wù)器有不同的配置,web 服務(wù)器 apache、nginx、IIS ,應(yīng)用服務(wù)器 tomcat 等配置都不盡相同;
協(xié)商緩存
1.Last-Modified:值為資源最后更新時間,隨服務(wù)器 Response 返回
2.If-Modified-Since:通過比較兩個時間來判斷資源在兩次請求期間是否有過修改,如果沒有修改,則命中協(xié)商緩存。
3.ETag:表示資源內(nèi)容的唯一標識,隨服務(wù)器 Response 返回。
Web 服務(wù)器響應(yīng)請求時,告訴瀏覽器當(dāng)前資源在服務(wù)器的唯一標識
注:HTTP 中并沒有指定如何生成 ETag,哈希是比較理想的選擇。
4.If-None-Match
服務(wù)器通過比較請求頭部的 If-None-Match 與當(dāng)前資源的 ETag 是否一致來判斷資源是否在兩次請求之間有過修改,如果沒有修改,則命中協(xié)商緩存。
三、緩存流程解析
看完上面的概念,我們來看看緩存流程是怎樣的?先來看看下面這張圖:

如上圖所示:
1.瀏覽器會先檢測強緩存類型(Cache-Control 或者 Expires)是否有效;
2.如果命中了強緩存,則直接從本地獲取緩存資源;
3.當(dāng)強緩存沒有命中時,客戶端會發(fā)送請求到服務(wù)器,服務(wù)器通過另一些 Request Header 驗證這個資源是否命中協(xié)商緩存,稱為 HTTP 再驗證,如果命中,服務(wù)器將請求返回,但不返回資源,而是告訴客戶端直接從緩存中獲取,客戶端收到返回后就會從緩存中獲取資源;
4.強緩存不會發(fā)送請求到服務(wù)器,但協(xié)商緩存會發(fā)送服務(wù)器請求;
5.當(dāng)協(xié)商緩存也沒命中時,服務(wù)器就會將資源發(fā)送回客戶端。
需要注意:
1.強緩存和協(xié)商緩存共同之處在于,如果命中緩存,服務(wù)器都不會返回資源;
2.當(dāng) F5 刷新網(wǎng)頁時,跳過強緩存,但是會檢查協(xié)商緩存;
3.當(dāng) Ctrl + F5 強制刷新頁面時,直接從服務(wù)器加載,跳過強緩存和協(xié)商緩存;
四、不會緩存的情況
當(dāng)然并不是所有請求都能被緩存,無法被瀏覽器緩存的請求如下:
1.HTTP 信息頭中包含 Cache-Control:no-cache ,pragma:no-cache(HTTP1.0),或Cache-Control: max-age=0 等告訴瀏覽器不用緩存的請求;
2.需要根據(jù) Cookie,認證信息等決定輸入內(nèi)容的動態(tài)請求是不能被緩存的;
3.經(jīng)過 HTTPS 安全加密的請求;
4.POST 請求無法被緩存;
5.HTTP 響應(yīng)頭中不包含 Last-Modified/Etag,也不包含 Cache-Control/Expires 的請求無法被緩存;
五、小故事大道理
上文對整個概念做了闡述,還是不夠形象,我們來通過幾個小故事生動理解一下:
故事一:Last-Modified
瀏覽器:Hi,我需要 jartto.min.js 這個文件,如果是在 Last-Modified: Fri Feb 15 2019 19:57:31 GMT 之后修改過的,請發(fā)給我。
服務(wù)器:(檢查文件的修改時間)
服務(wù)器:Oh,這個文件在那個時間之后沒有被修改過,你已經(jīng)有最新的版本了。
瀏覽器:太好了,那我就顯示給用戶了。
故事二:ETag
瀏覽器:Hi,我需要 jartto.css 這個文件,有沒有不匹配 3c61f-1c1-2aecb436 這個串的
服務(wù)器:(檢查 ETag…)
服務(wù)器:Hey,我這里的版本也是 3c61f-1c1-2aecb436,你已經(jīng)是最新的版本了
瀏覽器:好,那就可以使用本地緩存了
看完這兩個小故事,是否對協(xié)商緩存有了更清晰的認識了。