瀏覽器 & HTTP 緩存策略

緩存策略

瀏覽器的緩存策略是依靠 HTTP Header 來實現的,共分爲兩種:web

  • 強緩存
  • 協商緩存

強緩存

強緩存是指在緩存期間,請求不會發送到服務器,瀏覽器直接返回緩存結果,須要設置 Header:算法

  • expires
  • Cache-Control

expires

expires: Wed, 10 Oct 2020 09:51:00 GMT

expires 是 HTTP/1.0 中用於控制網頁緩存的字段,其值表明服務器返回該請求結果的緩存到期時間,也就是說,再次發起一樣的請求時,若是客戶端時間小於 Expires 的值,瀏覽器直接返回緩存結果。chrome

因爲 expires 是採用客戶端時間去和緩存失效時間作對比,但客戶端時間是能夠作修改的,若是客戶端時間和服務端時間並不一樣步,就會致使強緩存失效,或者時效變少。瀏覽器

因此,在 HTTP/1.1 中增長了 cache-control 頭。緩存

cache-control

cache-control 常見值爲:服務器

  • public:全部內容都將被緩存(客戶端和代理服務器均可緩存)
  • private:全部內容只有客戶端能夠緩存,默認爲 private
  • no-cache:客戶端緩存內容,可是否使用緩存須要通過協商緩存來決定
  • no-store:全部內容都不會被緩存
  • max-age=xxx:緩存內容將在 xxx 秒以後失效

咱們來看個例子:
image.png網絡

這個例子中,expires 和 cache-control 都被設置了,可是 cache-control 優先級高,因此該資源會在 2592000 秒(也就是 30 天)後失效。學習

咱們能夠得出 2 個結論:this

  1. 當 expires 和 cache-control 同時存在時,只有 cache-control 生效。
  2. 在某些不支持 HTTP/1.1 的環境下,expires 就會發揮用處,現階段它的存在只是爲了兼容性

Memory Cache & Disk Cache

image.png

當咱們 F12 查看瀏覽器網絡請求的時候,確定看到過這樣的信息,from memory cache(內存緩存)和 from disk cache(磁盤緩存)。spa

當請求命中強緩存時,瀏覽器就會從內存或者磁盤中將緩存的資源返回來,請求不會到達服務器。

那麼,哪些資源緩存在 memory,哪些緩存在 disk 呢?

關於 memory cache 和 disk cache,Chrome 官方有這麼一段描述:

Caching
Chrome employs two caches — an on-disk cache and a very fast in-memory cache. The lifetime of an in-memory cache is attached to the lifetime of a render process, which roughly corresponds to a tab. Requests that are answered from the in-memory cache are invisible to the web request API. If a request handler changes its behavior (for example, the behavior according to which requests are blocked), a simple page refresh might not respect this changed behavior. To make sure the behavior change goes through, call handlerBehaviorChanged()to flush the in-memory cache. But don't do it often; flushing the cache is a very expensive operation. You don't need to call handlerBehaviorChanged()after registering or unregistering an event listener.

以上引用自 Chrome API

讀取 memory 中的緩存資源,確定要比讀取 disk 中的更快,可是 memory 中的緩存,會隨着進程的釋放而釋放,也就是說,一旦咱們關閉 Tab 標籤,memory 中的緩存也就沒有了。

那麼哪些資源會被緩存到 memory,哪些會緩存到 disk 中呢?關於這點我也沒有找到定論,大多數的觀點以下,供你們參考:

  • 大文件,優先緩存至 disk,小文件優先緩存至 memory
  • 當內存佔用率高的狀況下,優先緩存至 disk

協商緩存

若是請求沒有命中強緩存,或者強緩存失效後,就須要向服務器發起請求,驗證資源是否有更新,這個過程叫作協商緩存。

當瀏覽器發起請求驗證資源時,若是資源沒有改變,那麼服務器返回 304 狀態碼,而且更新瀏覽器緩存有效期;若是資源發生改變,那麼服務器返回 200 狀態碼,而且返回相應資源,更新瀏覽器緩存有效期。

那麼服務器如何肯定資源有沒有更新呢,這裏就要用到如下 2 組 HTTP 頭。

last-modified & if-modified-since

last-modified 表示文件的最後修改日期,由服務器添加到 Response Header 中;if-modified-since 由瀏覽器添加到 Request Header 中,是上一次該資源的 last-modified 值。

服務器收到請求後,會將 if-modified-since 和服務器上該文件的修改時間戳進行比對,若是超過了緩存時間,那麼則返回最新的資源,200 狀態碼,若是還在緩存有效期內,則返回 304 狀態碼。

image.png
image.png

上面這個例子能夠看到:

  • Request Header 中 if-modified-since: Fri, 20 Dec 2019 12:44:01 GMT
  • Response Header 中 last-modified: Fri, 20 Dec 2019 12:44:01 GMT

這裏服務器將 if-modified-since 的時間和服務器上文件的修改時間作比對,發現仍在緩存時間有效期內,因此直接返回 304 狀態碼,並不返回文件資源,由瀏覽器提供緩存好的資源。

可是 last-modified 也有它的缺點:

  • 若是服務器上的文件被打開過,及時沒有修改,它的修改時間戳也會改變,就會致使 last-modified / if-modified-since 失效,服務器再次返回一樣的資源
  • last-modified / if-modified-since 是以秒爲單位,若是在秒之內文件發生了修改,那麼根據這組 Header 頭服務器會認爲文件沒有修改,依然命中協商緩存,返回老的資源

由於以上這些問題,因而在 HTTP/1.1 出現了 etag / if-none-match。

etag & if-none-match

etag 相似於文件指紋,能夠對文件內容作摘要算法,好比 md5,生成的值做爲 etag 的值,由服務器添加到 Response Header 中,瀏覽器再次請求該資源時,會在 Request Header 中添加 if-none-match 頭,值爲上次 etag 的值,服務器收到請求後,會對請求資源再次作相同的摘要算法,和 if-none-match 值進行比對,若是不同,說明資源更新了,返回 200 以及更新後的資源文件,若是相同,說明文件沒有被修改,則返回 304,由瀏覽器返回緩存資源。

總結來講,last-modified / if-modified-sice 和 etag / if-none-match,就是將服務器返回的某一個值,由瀏覽器在發送請求的時候帶回去,服務器拿到值後和本地文件的某個屬性進行判斷,來決定是否返回新的資源,仍是由瀏覽器返回緩存資源,這個過程,就叫作協商緩存。

相似於 expires 和 cache-control,etag / if-none-match 的優先級要比 last-modified / if-modified-since 高。

若是什麼緩存策略都沒有設置,那麼瀏覽器會採用一個啓發式的算法,一般會讀取 Response Header 中的 date 頭,減去 last-modified 值的 10% 做爲緩存時間。

總體流程圖

image.png

實際場景

學習了上面的緩存策略,在實際場景中咱們該如何應用呢?

頻繁變更的資源

  1. 徹底不緩存,cache-control: no-store
  2. 協商緩存,cache-control: no-cache,使瀏覽器每次請求都會走服務器,而後配合 etag 或者 last-modified 來驗證資源是否有效,這樣對比徹底不緩存來講,雖然沒法減小 HTTP 請求到達服務器的次數,可是能夠顯著減小響應數據的大小

文件

  1. HTML 文件不設緩存
  2. CSS、JS以及圖片等文件資源,能夠設置一個較長的緩存有效期,好比一年,cache-control: max-age=31536000,只有當 HTML 文件引入的文件名發生變化時,纔會去下載最新的資源文件,不然就一直使用緩存
相關文章
相關標籤/搜索