http學習筆記——瀏覽器緩存機制

前言

作為前端開發,我們在web開發的過程中需要調用后端接口,用node搭建服務器或者寫一些中間件對數據進行封裝處理等等,必不可少地會和http打上交道,所以我們都要掌握http各方面的知識。

說到性能優化問題,一定會提到http緩存,如何利用好http緩存機制,理解http緩存的整個過程和http如何設置緩存,把這些都弄懂后會對我們以后在項目實踐中都會有很大幫助。本篇文章將會和大家分享一下筆者對http緩存機制的一些知識整理和總結。

與緩存相關的http頭部字段

我們先看看http頭部中與緩存相關的一些字段的基本概念和用法。

Pragma

該字段來自http1.0時代,當其設置為no-cache的時候和Cache-Control: no-cache效果一樣,意為無緩存,客戶端不會讀取緩存,直接向服務器發起請求。因為是http1.0留下的遺物,僅為了做向后的兼容。

pragma

Expires

該字段也是來自http1.0時代,用于控制緩存時間。例如設置了Thu, 18 Jul 2019 08:43:30 GMT,即告訴瀏覽器如果沒有超過這個時間,將不會向服務器發起請求。

Expires存在兩個缺點:

  1. Expires的值是一個時間值。這就要求了客戶端和服務器端需要時間嚴格同步。否就會導致緩存失效。
  2. 當Expires定義的時間過期了,服務器需要重新配置一個新的時間。
expires

cache-control

http1.1新增了 Cache-Control 字段,用來定義緩存過期時間,若報文中同時出現了 Pragma、Expires 和 Cache-Control,會以 Cache-Control 為準。(網上也有Pragma優先級高于Cache-Control的說法,但是一般設置了Pragma: no-cache的話也會設置Cache-Control: no-cache的吧-.-)

先看看cache-control的常用設置值

cache-directive 描述
no-cache 不使用緩存,強制向服務器請求資源
no-store 所有內容都不會被緩存
public 資源將會被客戶端和代理服務器緩存
private 資源將會被客戶端緩存但不會被代理服務器緩存
max-age 緩存資源的最大時間段
s-maxage 同上, 依賴public設置, 覆蓋max-age, 且只在代理服務器上有效.
max-stale 指定時間內, 即使緩存過時, 資源依然有效
min-fresh 緩存的資源至少要保持指定時間的新鮮期
must-revalidation / proxy-revalidation 作用與no-cache類似,強制重新向服務器(或代理)發起驗證
only-if-cached 只從緩存中獲取資源,若沒有緩存則返回504
cachecontrol1

cache-control字段可以包含以上多個值,但是最終會選擇最為保守的方案。

cachecontrol2

Last-Modified & If-Modified-Since & If-Unmodified-Since

當客戶端第一次發起請求時,服務端會返回狀態碼200以及客戶端請求的資源,同時響應頭部會帶有Last-Modified字段,標記此文件在服務器最后修改的時間。

last-modified

而下次客戶端再次發起請求的時候,請求頭部就會帶有If-Modified-Since或者If-Unmodified-Since的字段,他們的值是上一次響應頭部Last-Modified字段的值,用于校驗資源是否過期。

若使用If-Modified-Since則服務端會判斷此時間后此文件是否修改過,如果沒有修改過則使用緩存資源,返回304,否則將獲取資源返回200.

若使用If-Unmodified-Since,則是相反的情況,若資源未修改過則獲取資源,否則返回412(Precondition Failed)響應。它常用于兩個場景:

  1. 不安全的請求, 比如說使用post請求更新wiki文檔, 文檔未修改時才執行更新
  2. 與 If-Range 字段同時使用時, 可以用來保證新的片段請求來自一個未修改的文檔

當遇到下面情況時,If-Unmodified-Since 字段會被忽略:

  1. Last-Modified值對上了(資源在服務端沒有新的修改)
  2. 服務端需返回2XX和412之外的狀態碼
  3. 傳來的指定日期不合法

Last-Modified存在的問題

  1. 服務器端的靜態資源通常需要編譯打包, 可能出現資源內容沒有改變, 而Last-Modified卻改變的情況.
  2. 某些文件修改非常頻繁,比如在秒以下的時間內進行修改,If-Modified-Since無法檢查到。
  3. 某些服務器不能精確的得到文件的最后修改時間。

Etag & If-Match & If-None-Match

為了解決以上Last-Modified存在的問題,http1.1還提出另外一個字段——Etag。Etag,實體首部字段,服務器資源的唯一標識符, 客戶端可以根據ETag值緩存數據, 節省帶寬。因此Etag的優先級高于Last-Modified。

服務器會通過某種算法,給資源計算得出一個唯一標志符(比如md5標志),在把資源響應給客戶端的時候,會在實體首部加上“ETag: 唯一標識符”一起返回給客戶端。

etag

當再次向服務器發起請求時,請求頭部會發送If-Match或者If-None-Match字段,服務器收到請求后則將其與被請求資源的唯一標識進行比對。

If-None-Match,若不同,說明資源又被改動過,則響應整片資源內容,返回狀態碼200;若相同,說明資源無新修改,則響應HTTP 304,告知瀏覽器繼續使用所保存的cache。

If-Match,若不同,則返回412(Precondition Failed) 狀態碼給客戶端。否則服務器直接忽略該字段。其應用場景是客戶端走PUT方法向服務端請求上傳/更替資源,這時候可以通過 If-Match 傳遞資源的ETag。

使用Etag注意兩點:

  1. 如果資源是走分布式服務器(比如CDN)存儲的情況,需要這些服務器上計算ETag唯一值的算法保持一致,才不會導致明明同一個文件,在服務器A和服務器B上生成的ETag卻不一樣。
  2. 如果 Last-Modified 和 ETag 同時被使用,則要求它們的驗證都必須通過才會返回304,若其中某個驗證沒通過,則服務器會按常規返回資源實體及200狀態碼。

http緩存策略

做好前期的知識鋪墊,馬上扔個流程圖上來

http

我們看到圖中不同階段有不同的緩存策略,我們逐一看看。

過期策略(命中強緩存)

過期策略主要是通過Expires和CacheControl來判斷緩存是否已經過期,若兩者都沒有設置的話,則使用瀏覽器默認的一套‘10%’算法來進行判斷,通常會取響應頭的Date_value - Last-Modified_value值的10%作為緩存時間。

假如緩存沒有過期則不向瀏覽器發出請求了,但是抓包的時候還是返回200 ok,但是留意了,會有Provisional headers are shown 的提示,說明就是瀏覽器并未發出請求, 緩存依然有效。

guoqi

(這坑很大啊,明明沒有向瀏覽器發起請求,還顯示200來嚇唬人-.-)

這時在Chrome里面會出現200(from disk cache)和200(from memory cache)的情況。官方解釋如下:

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會使用磁盤緩存和內存緩存,內存緩存是直接從內存中讀取的,所以速度更快。內部具體的規則還不大了解,估計是根據渲染刷新方式和文件大小決定的。

假如緩存過期了則走下一步協商策略。

協商策略

協商策略是通過Last-Modified和Etag字段向服務器發起驗證能否使用緩存資源,若驗證通過,則返回304狀態碼,根據響應頭更新緩存,使用緩存資源。

xieshang

若沒有通過校驗,則向服務器獲取資源,返回200,并將響應內容存進緩存。

存儲策略

這沒啥好說的,就是將響應內容存入緩存或者根據響應內容更新緩存。

綜上,再看回這個流程圖,我們梳理一下整個過程。

  1. 客戶端首次發起請求,沒有緩存數據,向服務器請求數據,服務器返回數據和緩存規則,并存入緩存。
  2. 客戶端再次發起請求,檢測是否有緩存,若有緩存,則檢測緩存是否過期,若緩存沒有過期,則使用緩存數據。(過期策略)
  3. 若緩存數據已過期,則向服務器發起校驗,驗證緩存是否有效,若通過驗證,則使用緩存,返回304;反之向服務器發起請求,返回200。(協商策略)

參考文章

瀏覽器緩存控制

瀏覽器緩存機制剖析

http緩存淺談

徹底弄懂HTTP緩存機制及原理

HTTP緩存控制小結

你應該知道的瀏覽器緩存知識

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 瀏覽器對于請求資源, 流程如圖所示: 可以看到瀏覽器的緩存機制分為兩個部分: 1、當前緩存是否過期? 2、服務器中...
    zhoulujun閱讀 1,222評論 0 3
  • 淺談瀏覽器Http的緩存機制 ? ? ? ? ? ? ? ? 針對瀏覽器的http緩存的分析也算是老生常談了,每隔...
    meng_philip123閱讀 1,036評論 0 10
  • 針對瀏覽器的http緩存的分析也算是老生常談了,每隔一段時間就會冒出一篇不錯的文章,其原理也是各大公司面試時幾乎必...
    全端玩法閱讀 896評論 0 9
  • 針對瀏覽器的http緩存的分析也算是老生常談了,每隔一段時間就會冒出一篇不錯的文章,其原理也是各大公司面試時幾乎必...
    單純的土豆閱讀 404評論 0 2
  • 文/獵頭王 來自不同的方向 匯入總流的同時 并在一起 你搭出你的槳,說 這是我的生命 我伸出我的櫓,說 這是我的真...
    紐森獵頭王凡閱讀 284評論 2 1