理解 Web 緩存

提到 Web 緩存大家都會覺得很簡單,不就是檢查資源是否有緩存,如果有就加以利用。如果追究下去,多數人還能扯出

cache-control, last-modified, etag 之類的名詞,但如果真的考究一下這些字段之間有什麼區別,又是怎麼工作的,其實很多人只有一個極為模糊的認識,所以寫一篇文章來梳理一下 Web 緩存的工作方式。


緩存不僅僅是瀏覽器的事情

很多人對 Web 緩存的認識就是瀏覽器判斷是否使用緩存,但緩存不是瀏覽器本身能夠完成的事情,因為在沒有服務器端的其他信息的情況下瀏覽器是無法判斷一個資源是否過期的。代理緩存,CDN 緩存等不在本文的討論範圍內。


緩存的控制通過 Headers 傳遞信息

因為針對緩存的控制需要瀏覽器和服務器端協同完成,所以他們需要一個傳遞的信息的方式,事實上目前的 Web 緩存主要通過 Headers 來傳遞信息。


以一張圖片為例

一張圖片資源為例,我們可以打開 Chrome 的開發者工具,隨便找一個 200(from cache) 的資源,可以看到請求報文和響應報文的 Headers。

理解 Web 緩存


cache-control 和 max-age

cache-control 大概是最廣為人知的控制緩存的 Headers 了,這也是最簡單的緩存控制策略,即瀏覽器通過最大生存時間來判斷資源的緩存是否有效。

如圖所見,來自服務器端的 response headers 的 Headers 中有 cache-control: max-age=93312000,這就是告訴瀏覽器這個資源的生存時間,在這個時間以內,瀏覽器不需要向服務器端再做任何確認,直接使用即可。下面我們也可以看到 request headers 一欄是空的。因為瀏覽器根本沒有發出請求,這裡顯示的 response headers 是之前的請求中緩存的。


expires

我們注意到在緩存的 response headers 裡還有一個 expires: Sat, 24 Aug 2019 09:03:00 GMT 字段。這個字段的意義實際上和 cache-control: max-age 的效果是相似的,在指定的時間之前瀏覽器都可以認為緩存是有效的。但當兩個字段同時存在時,expires 會被 cache-control 覆蓋。


304 Not Modified

上面的緩存策略只能很簡單的讓瀏覽器來確定緩存是否有效,而瀏覽器能夠依賴的只有上次請求時服務器端留給它的資源存活時間。我們不能把存活時間設成永遠,因為可能什麼時候我們會更新資源,但隔一段時間重新請求一次並沒有改變的資源同樣浪費帶寬。所以我們必須要有讓服務器告訴瀏覽器緩存仍然有效的方法,那便是 304 Not Modified。

在服務器端判斷緩存仍然有效時將會返回狀態碼 304 的響應。

那麼服務器如何判斷瀏覽器持有的緩存是否有效呢?這就需要瀏覽器將一些信息傳遞給服務器。

理解 Web 緩存


If-None-Match/ETag

採用的是 ETag 來判斷緩存是否有效,服務器端會在 response headers 中返回 ETag(文件的 hash):

ETag:"2afd9676ae9046ed99dedd4635bb6e4a"

而當資源改變時 ETag 也會發生改變。瀏覽器在發起請求時在 If-None-Match字段攜帶緩存的 ETag:

If-None-Match:"2afd9676ae9046ed99dedd4635bb6e4a-gzip"

服務器接到請求後如果一致(即資源沒有修改),則返回 304 Not Modified,否則返回新的資源(200)。


If-Modified-Since/Last-Modified

除了文件特徵碼之外也可以通過上次修改時間,服務器端返回資源時通過 Last-Modified 攜帶資源修改時間,瀏覽器通過 If-Modified-Since 攜帶緩存中的資源的修改時間。


ETag 和 Last-Modified 的區別

Last-Modified 有個缺點就是它是精確到秒的,如果一秒中資源多次服務器不會感知到緩存失效,但這不是一個常見的需求。

而一般不推薦使用 ETag,原因有幾點

【1】Last-Modified 的缺點基本可以忽略不計

【2】ETag 本身需要消耗 CPU,而它的優先級比 Last-Modified 高,當它存在時服務器無論 Last-Modified 是否存在都會使用它判斷

【3】ETag 在分佈式系統中生成的值可能不一樣,會導致緩存失效

理解 Web 緩存


分享到:


相關文章: