瀏覽器的強緩存和協商緩存

瀏覽器的強緩存和協商緩存

原文連接: https://github.com/yiliang114...

這裏說的緩存是指瀏覽器(客戶端)在本地磁盤中對訪問過的資源保存的副本文件。css

瀏覽器緩存主要有如下幾個優勢:html

  1. 減小重複數據請求,避免經過網絡再次加載資源,節省流量。
  2. 下降服務器的壓力,提高網站性能。
  3. 加快客戶端加載網頁的速度, 提高用戶體驗。

瀏覽器緩存分爲強緩存和協商緩存,二者有兩個比較明顯的區別:nginx

  1. 若是瀏覽器命中強緩存,則不須要給服務器發請求;而協商緩存最終由服務器來決定是否使用緩存,即客戶端與服務器之間存在一次通訊。
  2. chrome 中強緩存(雖然沒有發出真實的 http 請求)的請求狀態碼返回是 200 (from cache);而協商緩存若是命中走緩存的話,請求的狀態碼是 304 (not modified)。 不一樣瀏覽器的策略不一樣,在 Fire Fox中,from cache 狀態碼是 304.
其中 from cache 會分爲 from disk cache 和 from memory cache. 從內存中獲取最快,可是是 session 級別的緩存,關閉瀏覽器以後就沒有了。
image.png

請求流程

瀏覽器在第一次請求後緩存資源,再次請求時,會進行下面兩個步驟:git

  1. 瀏覽器會獲取該緩存資源的 header 中的信息,根據 response header 中的 expirescache-control 來判斷是否命中強緩存,若是命中則直接從緩存中獲取資源。
  2. 若是沒有命中強緩存,瀏覽器就會發送請求到服務器,此次請求會帶上 IF-Modified-Since 或者 IF-None-Match, 它們的值分別是第一次請求返回 Last-Modified或者 Etag,由服務器來對比這一對字段來判斷是否命中。若是命中,則服務器返回 304 狀態碼,而且不會返回資源內容,瀏覽器會直接從緩存獲取;不然服務器最終會返回資源的實際內容,並更新 header 中的相關緩存字段。

借用網上的一張圖片github

image.png

強緩存

強緩存是根據返回頭中的 Expires 或者 Cache-Control 兩個字段來控制的,都是表示資源的緩存有效時間。chrome

  • Expireshttp 1.0 的規範,值是一個GMT 格式的時間點字符串,好比 Expires:Mon,18 Oct 2066 23:59:59 GMT 。這個時間點表明資源失效的時間,若是當前的時間戳在這個時間以前,則斷定命中緩存。有一個缺點是,失效時間是一個絕對時間,若是服務器時間與客戶端時間誤差較大時,就會致使緩存混亂。而服務器的時間跟用戶的實際時間是不同是很正常的,因此 Expires 在實際使用中會帶來一些麻煩。
  • Cache-Control這個字段是 http 1.1 的規範,通常經常使用該字段的 max-age 值來進行判斷,它是一個相對時間,好比 .Cache-Control:max-age=3600 表明資源的有效期是 3600 秒。而且返回頭中的 Date 表示消息發送的時間,表示當前資源在 Date ~ Date +3600s 這段時間裏都是有效的。不過我在實際使用中經常遇到設置了 max-age 以後,在 max-age 時間內從新訪問資源卻會返回 304 not modified ,這是因爲服務器的時間與本地的時間不一樣形成的。固然 Cache-Control 還有其餘幾個值能夠設置, 不過相對來講都不多用了:後端

    • no-cache 不使用本地緩存。須要使用協商緩存。
    • no-store直接禁止瀏覽器緩存數據,每次請求資源都會向服務器要完整的資源, 相似於 network 中的 disabled cache
    • public 能夠被全部用戶緩存,包括終端用戶和 cdn 等中間件代理服務器。
    • private 只能被終端用戶的瀏覽器緩存。

若是 Cache-ControlExpires 同時存在的話, Cache-Control 的優先級高於 Expires瀏覽器

協商緩存

協商緩存是由服務器來肯定緩存資源是否可用。 主要涉及到兩對屬性字段,都是成對出現的,即第一次請求的響應頭帶上某個字, Last-Modified 或者 Etag,則後續請求則會帶上對應的請求字段 If-Modified-Since或者 If-None-Match,若響應頭沒有 Last-Modified 或者 Etag 字段,則請求頭也不會有對應的字段。緩存

  • Last-Modified/If-Modified-Since 兩者的值都是 GMT 格式的時間字符串, Last-Modified 標記最後文件修改時間, 下一次請求時,請求頭中會帶上 If-Modified-Since 值就是 Last-Modified 告訴服務器我本地緩存的文件最後修改的時間,在服務器上根據文件的最後修改時間判斷資源是否有變化, 若是文件沒有變動則返回 304 Not Modified ,請求不會返回資源內容,瀏覽器直接使用本地緩存。當服務器返回 304 Not Modified 的響應時,response header 中不會再添加的 Last-Modified 去試圖更新本地緩存的 Last-Modified, 由於既然資源沒有變化,那麼 Last-Modified 也就不會改變;若是資源有變化,就正常返回返回資源內容,新的 Last-Modified 會在 response header 返回,並在下次請求以前更新本地緩存的 Last-Modified,下次請求時,If-Modified-Since會啓用更新後的 Last-Modified
  • Etag/If-None-Match, 值都是由服務器爲每個資源生成的惟一標識串,只要資源有變化就這個值就會改變。服務器根據文件自己算出一個哈希值並經過 ETag字段返回給瀏覽器,接收到 If-None-Match 字段之後,服務器經過比較二者是否一致來斷定文件內容是否被改變。與 Last-Modified 不同的是,當服務器返回 304 Not Modified 的響應時,因爲在服務器上ETag 從新計算過,response header中還會把這個 ETag 返回,即便這個 ETag 跟以前的沒有變化。
HTTP 中並無指定如何生成 ETag,能夠由開發者自行生成,哈希是比較理想的選擇。

爲何要有 Etag

HTTP1.1Etag 的出現主要是爲了解決幾個 Last-Modified 比較難解決的問題:服務器

  • 一些文件也許會週期性的更改,可是內容並不改變(僅僅改變的修改時間),這個時候咱們並不但願客戶端認爲這個文件被修改了,而從新 GET;
  • 某些文件修改很是頻繁,好比在秒如下的時間內進行修改,(比方說 1s 內修改了 N 次),If-Modified-Since 能檢查到的粒度是秒級的,使用 Etag 就可以保證這種需求下客戶端在 1 秒內能刷新 N 次 cache。
  • 某些服務器不能精確的獲得文件的最後修改時間。

優先級

Cache-Control  > expires > Etag > Last-Modified

用戶行爲對緩存的影響

簡單說就是 F5 刷新的時候,會暫時禁用強緩存

通過對 qq、fire fox 、safari 、chrome 這幾個瀏覽器的訪問同一個頁面測試我發現,不一樣的瀏覽器在 F5 刷新的時候 ,同一個文件 qq 、fire fox 瀏覽器會返回 304 Not Nodified,在請求頭中不攜帶 Expires/Cache-Control; 而 chrome 和 safari 刷新的時候,會返回 200 from cache, 沒有真正發起請求,走強緩存。可見不一樣的瀏覽器反饋是不一致的,因此下面表格中"F5 刷新"時 Expires/Cache-Control 會無效我認爲是存在必定爭議的。

而 Ctrl + F5 強制刷新的時候,會暫時禁用強緩存和協商緩存。

在寫這篇博客時,對於我僅僅測試了一個瀏覽器以後便寫了無效(由於網上大多數帖子寫了無效,我也覺得我驗證經過了),對指出這個問題的羣友,表示感謝,但願其餘人不會被我誤導。
用戶操做 Expires/Cache-Control Last-Modied/Etag
地址欄回車 有效 有效
頁面連接跳轉 有效 有效
新開窗口 有效 有效
前進回退 有效 有效
F5 刷新 無效(有爭議,不一樣瀏覽器反饋不一致) 有效
Ctrl+F5 強制刷新 無效 無效

如何設置強緩存和協商緩存

  1. 後端服務器,寫入代碼邏輯中:

    res.setHeader('max-age': '3600 public')
    res.setHeader(etag: '5c20abbd-e2e8')
    res.setHeader('last-modified': Mon, 24 Dec 2018 09:49:49 GMT)
  2. Nginx 配置

    add_header Cache-Control "max-age=3600"

    通常來講,經過 nginx 靜態資源服務器,會默認給資源帶上強緩存、協商緩存的 header 字段。

    image.png

兩個示例

  1. 若是在 cache-control定義的 max-age 時間以內,js, css 文件會走強緩存,http 狀態碼是 200, 跟服務器也並不會有交互。可是第一個文件 index.html 文件, 每次回車或者刷新都是狀態碼都是 304 ,由於它的請求頭中默認每次都攜帶了 Cache-Control: max-age=0

    image.png

    image.png

  2. js css 文件 cache-control 超時以後,從新按回車會走協商緩存,請求服務器發現資源沒有改變,因而返回 304 ,瀏覽器從緩存中獲取內容,從 size 中也能夠看出端倪, 幾百 B 的包不是靜態資源的體積。

    image.png

三級緩存原理(大白話)

最後總結一下瀏覽器的三級緩存原理:

  1. 先去內存看,若是有,直接加載
  2. 若是內存沒有,擇取硬盤獲取,若是有直接加載
  3. 若是硬盤也沒有,那麼就進行網絡請求
  4. 加載到的資源緩存到硬盤和內存

參考文檔

from disk cache 與 from memory cache

http 協商緩存 VS 強緩存

相關文章
相關標籤/搜索