前端應用關於瀏覽器緩存策略問題

瀏覽器緩存類型

瀏覽器緩存的做用和好處無需多言,其根據是否須要向服務器從新發起 http 請求分爲強緩存協商緩存兩種類型。強緩存的優先級要高於協商緩存。css

強緩存

強緩存機制下瀏覽器首先查找本地緩存,若是命中則不會向服務器發起請求。此時返回 200 狀態碼,並帶有 from disk cachefrom memory cache 字樣。強緩存能夠經過設置兩種 HTTP Header 實現:ExpiresCache-Controlhtml

Memory Cache

Memory Cache 也就是內存中的緩存,主要包含的是當前頁面中已經獲取到的資源,好比頁面上已經下載的樣式、腳本、圖片等。讀取內存中的數據確定比磁盤快,內存緩存雖然讀取高效,但是緩存持續很短,會隨着進程的釋放而釋放。一旦咱們關閉 Tab 頁面,內存中的緩存也就被釋放了。既然內存緩存這麼高效,咱們是否是能讓數據都存放在內存中呢?這是不可能的。計算機中的內存必定比硬盤容量小得多,操做系統須要精打細算內存的使用,因此能讓咱們使用的內存必然很少。前端

Disk Cache

Disk Cache 也就是存儲在磁盤中的緩存,讀取速度慢點,可是什麼都能存儲到磁盤中,比之 Memory Cache 勝在容量和存儲時效性上。在全部瀏覽器緩存中,Disk Cache 覆蓋面基本是最大的。它會根據 HTTP Herder 中的字段判斷哪些資源須要緩存,哪些資源能夠不請求直接使用,哪些資源已通過期須要從新請求。絕大部分的緩存都來自 Disk Cache。nginx

瀏覽器會把哪些文件丟進內存中?哪些丟進磁盤中?關於這點,網上說法不一,不過如下觀點比較靠得住:算法

  • 對於大文件來講,大機率是不存儲在內存中的,反之優先;
  • 當前系統內存使用率高的話,文件優先存儲進磁盤。

Expires

Expires 用來指定緩存過時時間,是服務器端發的具體時間點。也就是說,Expires=請求時間 + max-age。Expires 是服務器響應消息頭字段,在響應 http 請求時告訴瀏覽器在過時時間前瀏覽器能夠直接從瀏覽器緩存讀取數據,而無需再次請求。瀏覽器

Expires 是 HTTP/1.0 的產物,受限於本地時間。若是修改了本地時間,可能會形成緩存失效。好比 Expires: Wed, 22 Oct 2018 08:30:00 GMT表示資源會在 Wed, 22 Oct 2018 08:30:00 GMT 後過時,須要再次請求。緩存

Cache-Control

在 HTTP/1.1中,Cache-Control 是最重要的規則,主要用於控制網頁緩存。好比當 Cache-Control:max-age=300時,則表明在這個請求正確返回時間(瀏覽器會記錄下來)的5分鐘內再次加載資源,就會命中強緩存。咱們重點看看以下幾個設置值:服務器

public

全部內容都將被緩存(客戶端和代理服務器均可緩存)。具體來講響應可被任何中間節點緩存,如 Browser <-- proxy <-- Server,中間的 proxy 能夠緩存資源,好比下次再請求同一資源時 proxy 直接把本身緩存的內容給 Browser 而再也不向 Server 要。負載均衡

private

全部內容只有客戶端能夠緩存,Cache-Control 的默認取值。具體來講,表示中間節點不容許緩存,對於 Browser <-- proxy <-- Server,proxy 會老老實實把 Server Browser,本身不緩存任何數據。當下次 Browser 再次請求時 proxy 會作好請求轉發而不是自做主張給本身緩存的數據。前端構建

no-cache

客戶端緩存內容,是否使用緩存則須要通過協商緩存來驗證決定。表示不使用 Cache-Control 的緩存控制方式作前置驗證,而是使用 Etag 或者 Last-Modified 字段來控制緩存。須要注意的是,no-cache 這個名字有一點誤導。設置了 no-cache 以後,並非說瀏覽器就再也不緩存數據,只是瀏覽器在使用緩存數據時,須要先確認一下數據是否還跟服務器保持一致。

no-store

全部內容都不會被緩存,既不使用強緩存,也不使用協商緩存。

max-age

max-age=xxx(xxx is numeric) 表示緩存內容將在 xxx 秒後失效。

Expires 和 Cache-Control 二者對比

其實這二者差異不大,區別就在於 Expires 是 HTTP/1.0 的產物,Cache-Control 是 HTTP/1.1 的產物。二者同時存在的話,Cache-Control 優先級高於 Expires。在某些不支持 HTTP1.1 的環境下,Expires 就會發揮用處。因此 Expires 實際上是過期的產物,現階段它的存在只是一種兼容性的寫法。

強緩存判斷是否緩存的依據來自因而否超出某個時間或者某個時間段,而不關心服務器端文件是否已經更新,這可能會致使加載文件不是服務器端最新的內容,那咱們如何獲知服務器端內容是否已經發生了更新呢?此時咱們須要用到協商緩存。

協商緩存

協商緩存就是強緩存失效後,瀏覽器攜帶緩存標識向服務器發起請求,由服務器根據緩存標識決定是否使用緩存的過程,主要有如下兩種狀況:

  • 協商緩存生效,返回 304 和 Not Modified。
  • 協商緩存失效,返回 200 和請求結果。

協商緩存能夠經過設置兩種 HTTP Header 實現:Last-Modified 和 ETag。

Last-Modified 和 If-Modified-Since

瀏覽器在第一次訪問資源時,服務器返回資源的同時,在 response header 中添加 Last-Modified 的 header,值是這個資源在服務器上的最後修改時間,瀏覽器接收後緩存文件和header。

Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT
瀏覽器下一次請求這個資源,瀏覽器檢測到有 Last-Modified 這個 header,因而添加 If-Modified-Since 這個 header,值就是 Last-Modified 中的值。服務器再次收到這個資源請求,會根據 If-Modified-Since 中的值與服務器中這個資源的最後修改時間對比,若是沒有變化,返回 304 和空的響應體,瀏覽器直接從緩存讀取。若是 If-Modified-Since 的時間小於服務器中這個資源的最後修改時間,說明文件有更新,則返回新的資源文件和 200。

ETag 和 If-None-Match

Etag 是服務器響應請求時返回當前資源文件的一個惟一標識(由服務器生成),只要資源有變化,Etag 就會從新生成。瀏覽器在下一次加載資源向服務器發送請求時,會將上一次返回的 Etag 值放到 request header 裏的 If-None-Match 裏,服務器只須要比較客戶端傳來的 If-None-Match 跟本身服務器上該資源的 ETag 是否一致,就能很好地判斷資源相對客戶端而言是否被修改過了。若是服務器發現 ETag 匹配不上,那麼直接以常規 GET 200 回包形式將新的資源(固然也包括了新的 ETag)發給客戶端。若是 ETag 是一致的,則返回 304 指示客戶端直接使用本地緩存便可。

Last-Modified 和 ETag 二者對比

  1. 在精確度上,Etag 要優於 Last-Modified。Last-Modified 的時間單位是秒,若是某個文件在 1 秒內改變了屢次,那麼他們的 Last-Modified 其實並無體現出來修改。可是 Etag 每次都會改變確保了精度。若是是負載均衡的服務器,各個服務器生成的 Last-Modified 也有可能不一致。
  2. 在性能上,Etag 要遜於 Last-Modified,畢竟 Last-Modified 只須要記錄時間,而 Eta g須要服務器經過算法來計算出一個 hash 值。
  3. 在優先級上,服務器校驗優先考慮 Etag。

緩存機制

強緩存優先級高於協商緩存,若強緩存(Expires 和 Cache-Control)生效則直接使用緩存,若不生效則進行協商緩存(Last-Modified / If-Modified-Since 和 Etag / If-None-Match)。協商緩存由服務器決定是否使用緩存,若協商緩存失效,那麼表明該請求的緩存失效,返回 200,從新返回資源和緩存標識,再存入瀏覽器緩存中;生效則返回 304,繼續使用緩存。

那若是什麼緩存策略都沒設置,瀏覽器會怎麼處理呢?對於這種狀況,瀏覽器會採用一個啓發式的算法,一般會取響應頭中的 Date 減去 Last-Modified 值的 10% 做爲緩存時間。

前端 SPA 應用緩存策略

首頁 index.html 緩存策略

因爲默認什麼都不設置的狀況下會應用強緩存,這樣就會致使每次 index.html 有更新時用戶端都不必定能及時獲得最新版本(常常須要用戶強制刷新或手動清除瀏覽器緩存)。建議 index.html 中設置 Cache-Control 值爲 no-cache 取消強緩存,使瀏覽器每次都請求服務器,而後配合 ETag 或者 Last-Modified 來協商驗證資源是否有效。這樣的作法雖然不能節省請求數量,可是能顯著減小響應數據大小且兼顧了及時更新的需求,另外因爲只有 index.html 這一個單頁須要這樣,所以這種方式明顯利大於弊。

靜態資源文件緩存策略

靜態資源文件如 css js 文件等,因爲前端構建打包輸出中對於這些文件會引入 hash 動態值,那麼每次有更新時加載他們的 URL 也都不相同。所以對於這些文件,咱們徹底能夠設置強緩存 Cache-Control 爲一個很大的值,好比半年或一年(以 nginx 舉例來講,能夠設置 expires 180d 等),在此期間內瀏覽器無需發起任何請求,直接使用本地緩存,最大化利用瀏覽器緩存。而在這些文件有更新的時候,因爲請求 URL 也變了,因此無需擔憂瀏覽器不能及時獲得最新版本。

相關文章
相關標籤/搜索