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

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