前言
在瀏覽器眾多緩存中的HTTP緩存可能很多人對這個的概念並沒有很清晰,每個人都知道進入一次網頁之後再刷新一次頁面,加載速度會比首次加載快非常多,每個人都知道這是瀏覽器緩存的magic,但是對此背後的原因可能不甚瞭解...
個人博客瞭解一下:obkoro1.com
當我們在談論HTTP緩存時我們在談論什麼:
我們實際上是在談論下面這兩種情況:
如上圖,瀏覽器對靜態資源的HTTP緩存有兩種情況,一種是強緩存(本地緩存),另一種是弱緩存(協商緩存)。
緩存流程:
瀏覽器第一次請求資源時:
瀏覽器第一次請求資源時,必須下載所有的資源,然後根據響應的header內容來決定,如何緩存資源。可能採用的是強緩存,也可能是弱緩存
瀏覽器後續請求資源時的匹配流程:
由上圖可以知道當瀏覽器請求一個靜態資源時的HTTP流程:
- 強緩存階段:先在本地查找該資源,如果發現該資源,並且其他限制也沒有問題(比如:緩存有效時間),就命中強緩存,返回200,直接使用強緩存,並且不會發送請求到服務器
- 弱緩存階段:在本地緩存中找到該資源,發送一個http請求到服務器,服務器判斷這個資源沒有被改動過,則返回304,讓瀏覽器使用該資源。
- 緩存失敗階段(重新請求):當服務器發現該資源被修改過,或者在本地沒有找到該緩存資源,服務器則返回該資源的數據。
強緩存與弱緩存的區別:
獲取資源形式: 都是從緩存中獲取資源的。
狀態碼: 強緩存返回200(from cache),弱緩存返回304狀態碼
請求(最大區別):
強緩存不發送請求,直接從緩存中取。
弱緩存需要發送一個請求,驗證這個文件是否可以使用(有沒有被改動過)。
強緩存:
強緩存是利用Expires或者Cache-Control,讓原始服務器為文件設置一個過期時間,在多長時間內可以將這些內容視為最新的。
若時間未過期,則命中強緩存,使用緩存文件不發送請求。
Cache-Control
Cache-Control 是http1.1中為了彌補Expires的缺陷而加入的,當Expires和Cache-Control同時存在時,Cache-Control優先級高於Expires。
選項:
可緩存性:
public: 表明響應可以被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存。
private: 只有用戶自己的瀏覽器能夠進行緩存,公共的代理服務器不允許緩存。
no-cache: 強制瀏覽器在使用cache拷貝之前先提交一個http請求到源服務器進行確認。http請求沒有減少,會減少一個響應體(文件內容),這種個選項類似弱緩存。
only-if-cached: 表明客戶端只接受已緩存的響應,並且不要向原始服務器檢查是否有更新的拷貝。
到期設置:
max-age=60:設置緩存存儲的最大週期,超過這個時間緩存被認為過期(單位秒)。 這裡是60秒
其他設置:
no-store: 告訴瀏覽器在任何情況下都不要進行cache,不在本地保留拷貝。
must-revalidate: 緩存必須在使用之前驗證舊資源的狀態,並且不可使用過期資源。
更多設置,移動MDN
// 示例
Cache-Control: no-cache, no-store, must-revalidate
Cache-Control:public, max-age=31536000
Cache-Control: max-age=3600, must-revalidate
http1.0時代的緩存 Expires+Pragma
Expires用於設置緩存到期時間:
指定緩存到期GMT的絕對時間,如果設了max-age,max-age就會覆蓋expires,如果expires到期需要重新請求。
Expires:Sat, 09 Jun 2018 08:13:56 GMT
有一個問題是由於使用具體時間,如果時間表示出錯或者沒有轉換到正確的時區都可能造成緩存生命週期出錯。
Pragma禁用緩存:
Pragma : no-cache 表示防止客戶端緩存,需要強制從服務器獲取最新的數據;
Pragma : no-cache //只有這一個用法 禁用緩存,強制從服務器獲取最新的數據;
強緩存命中 from memory cache & from disk cache
在測試的時候,看到命中強緩存時,有兩種狀態,200 (from memory cache) cache & 200 (from disk cache),於是去找了一下這兩者的區別:
memory cache: 將資源存到內存中,從內存中獲取。
disk cache:將資源緩存到磁盤中,從磁盤中獲取。
二者最大的區別在於:當退出進程時,內存中的數據會被清空,而磁盤的數據不會。
更詳細的介紹推薦這篇文章
弱緩存:
如果強緩存時間過期,或者沒有設置,導致未命中的話。就進入到了弱緩存的階段了,
Last-Modified & if-modified-since:
Last-Modified與If-Modified-Since是一對報文頭,屬於http 1.0。
last-modified是web服務器認為文件的最後修改時間,last-modified是第一次請求文件的時候,服務器返回的一個屬性。
Last-Modified: Sat, 09 Jun 2018 08:13:56 GMT
第二次請求這個文件時,瀏覽器把If-Modified-Since發送給服務器,詢問該時間之後文件是否被修改過。
If-Modified-Since: Sat, 09 Jun 2018 08:13:56 GMT // 跟Last-Modified的值一樣
ETag & If-None-Match
ETag與If-None-Match是一對報文,屬於http 1.1。
ETag是一個文件的唯一標誌符。就像一個哈希或者指紋,每個文件都有一個單獨的標誌,只要這個文件發生了改變,這個標誌就會發生變化。
ETag機制類似於樂觀鎖機制,如果請求報文的ETag與服務器的不一致,則表示該資源已經被修改過來,需要發最新的內容給瀏覽器。
ETag也是首次請求的時候,服務器返回的:
ETag: "8F759D4F67D66A7244638AD249675BE2" // 長這樣
If-None-Match也是瀏覽器發送到服務器驗證,文件是否改變的:
If-None-Match: "8F759D4F67D66A7244638AD249675BE2" // 跟ETag的值一樣
Etag/lastModified過程如下:
- 客戶端第一次向服務器發起請求,服務器將附加Last-Modified/ETag到所提供的資源上去
- 當再一次請求資源,如果沒有命中強緩存,在執行在驗證時,將上次請求時服務器返回的Last-Modified/ETag一起傳遞給服務器。
- 服務器檢查該Last-Modified或ETag,並判斷出該資源頁面自上次客戶端請求之後還未被修改,返回響應304和一個空的響應體。
同時使用兩個報文頭:
同時使用這兩個報文頭,
兩個都匹配才會命中弱緩存,否則將重新請求資源。Etag 主要為了解決 Last-Modified 無法解決的一些問題:
- 一些文件也許內容並不改變(僅僅改變的修改時間),這個時候我們不希望文件重新加載。(Etag值會觸發緩存,Last-Modified不會觸發)
- If-Modified-Since能檢查到的粒度是秒級的,當修改非常頻繁時,Last-Modified會觸發緩存,而Etag的值不會觸發,重新加載。
- 某些服務器不能精確的得到文件的最後修改時間。·
用戶操作行為與緩存
F5刷新導致強緩存失效。
ctrl+F5強制刷新頁面強緩存,弱緩存都會失效。
如何設置?
一般是服務器端設置這些請求頭的,我自己試了用阿里雲服務器設置Cache-Control,設置一下很方便的。
嗯,據說客戶端也是可以設置強弱緩存,但是找了半天不知道怎麼設置,如果有路過的大佬知道,可以指導一波^_^。
沒有設置強緩存,返回200
如下圖這種情況,就不太懂怎麼回事,下方的解釋也沒看明白,圖片內容出自這篇文章
結語
通過網絡重複請求資源既緩慢,成本又高,緩存和重用以前獲取的資源的能力成為優化性能很關鍵的一個方面,也是大廠面試時很頻繁出現的內容,掌握好這塊知識點是非常重要的,希望本文能給你帶來些收穫。
鏈接:https://juejin.im/post/5b1b563f5188257d9940e402
閱讀更多 前端圈 的文章