博客 / 詳情

返回

http-web緩存總結

友情提示:緩存什麼的,完全依賴相關http header頭信息來標記和判斷的哦

緩存讀取順序:

首先讀取本地緩存,如果條件滿足就取本地緩存,否則往後走代理緩存,同理,條件滿足就是從代理緩存取資源(可能存在多級代理緩存)

如果一條鏈路上的資源都不符合,那麼就去源服務器獲取

緩存優先級:Cache-Control > Expires > Etag > Last-Modified

緩存的分類和優先級

  • 強緩存 狀態碼 200 (比如 200 (from cache))

    • Expires 服務器下發的絕對時間,而判斷的時候以瀏覽器時間為準,客户端和服務器有可能會不一樣
    • Cache-Control 相對時間,以客户端相對時間為準
  • 協商緩存 狀態碼 304

    • Last-Modified If-Modified-Since
    • Etag If-None-Match

強緩存優先級高於協商緩存,強緩存不會詢問服務器,直接使用緩存。協商緩存會詢問服務器關於文件的可用性

==對於傳輸過程中的中間節點,本文都稱為代理服務器,包括proxy、CDN和緩存服務器==

緩存頭Cache-Control

可緩存性 (哪些節點可以進行緩存)

  • public 在這個請求的返回過程中的任何節點都可以對這個返回的內容進行緩存,比如代理服務器可以對其緩存
  • private 只有發起請求的節點才能進行緩存,其他節點都禁止緩存資源
  • no-cache 可以進行緩存,但是在使用之前,要去服務器先驗證緩存的有效性,有效的話才能使用,搭配max-age=0使用,不會直接從瀏覽器讀取相應的緩存文件,而是先向服務端發起請求確認瀏覽器的緩存是否過期來判斷是從瀏覽器加載還是從服務器加載
  • no-store 任何節點都不能進行緩存

到期時間

  • max-age = <seconds> 多少秒之後緩存內容過期
  • s-maxage = <seconds> 只在代理服務器生效。優先級大於max-age。如果s-maxage時間到了,代理服務器會去遠端讀取新的數據並更新緩存
  • max-stale = <seconds> 即便緩存過期了,只要在max-stale的範圍,則不需要請求新的緩存

重新驗證

  • must-revalidate 在設置了max-age過期之後,瀏覽器必須去源服務端獲取新的數據
  • proxy-revalidate 代理服務器數據過期後,必須去源服務端獲取新的數據

其他

  • no-transform 用在代理服務器,不允許對返回內容進行壓縮、格式轉換等

上述頭信息是規範,但是很多代理服務器不按這個來

缺點:Cache-Control為客户端緩存,服務端更新了文件之後,客户端並不第一時間更新緩存,這也是web開發中的常見問題

Cache-Control缺點的通用解決方案:在打包文件之後,根據靜態文件內容加上一串hash碼或者版本號,如果靜態文件內容沒變,則hash不會變,反之,靜態文件內容變化之後,hash碼變化,則靜態資源url發生變化,可以更新客户端緩存

舉例

我司的處理:可以看到,devTools的Size欄,提示出from memory cache,即讀取瀏覽器本地緩存

Cache-Control解決方案

示例代碼:這裏是用模板來加載的,support來填充,猜測可以在初始化請求的時候,通過請求配置接口,拿到對應的web資源的版本號的接口或者配置文件,然後再靜態資源去加載之前,將對應的版本號填充到對應的src或者link中

<script src="{#domain}/js/i18nlibs.js?v={#support}"></script>

資源驗證頭信息Last-Modified和Etag

Last-Modified

資源上次修改時間,主要配合If-Modified-Since或者If-Unmodified-Since使用:如果請求了一個資源的respose header裏面有Last-Modified頭信息指定了一個時間,下一次瀏覽器發起請求的時候,通過If-Modified-Since或者If-Unmodified-Since(通常使用If-Modified-Since,If-Unmodified-Since很少用)帶上那個時間,帶到服務器,服務器讀取並對比這個資源上次修改的時間,如果一致,則代表資源沒有被修改過,那麼瀏覽器可以繼續使用緩存,反之緩存不能使用

ps:如果資源是存在數據庫的,可以給資源加上一個update-at的字段加上修改時間作為Last-Modified時間返回給瀏覽器

Etag

更加嚴格的驗證方式,通過數據簽名的方式,根據資源的內容產生一個唯一的簽名,如果資源的內容產生了修改,那麼簽名就會更新,任何的修改都會導致簽名不一致,常用方式是對資源的內容進行hash計算產生簽名來標記資源。

配合If-Match或者If-Non-Match使用,下一次瀏覽器發請求會帶上If-Match或者If-Non-Match頭,頭裏面的值就是服務端上一次給出的Etag簽名,然後服務器對比簽名是否一致

http code 304資源沒有修改,可以直接讀取緩存,及時這時候服務端有了新的返回,也會被瀏覽器忽略,直接讀取緩存數據(寫個接口,而不是靜態資源文件來驗證一下)

tips:

chrome的devTools,當把Disable cache勾選上之後,瀏覽器就不往服務器發送關於緩存的頭信息了,這時候只能從服務器讀取最新的數據

緩存對比localStorage: 緩存文件不用自己去控制localStorage的讀寫呢

HTTP緩存流程圖

http-cache流程圖

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.