詳解Http緩存策略

什么是緩存

緩存 是應用程序中很重要的一個概念,在有大量數(shù)據(jù)交換的應用程序中,我們會采取一些方式將那些實時性要求不高的數(shù)據(jù)生成副本并存儲在某個相對來說可快速到達、訪問、獲取的倉庫,這樣在需要這些數(shù)據(jù)的時候我們直接從這個倉庫中獲取數(shù)據(jù)。

緩存的目的主要有兩點:

  1. 提升數(shù)據(jù)交換的性能(速度)
  2. 緩解服務器或數(shù)據(jù)庫的壓力

http緩存概述

當用戶開始訪問一個網(wǎng)站時,瀏覽器會從目標服務器獲取一些資源用以構建最終的web頁面,比如css、js、html等靜態(tài)文件。假設我們不采取任何措施,則用戶每次訪問這個網(wǎng)站都要發(fā)起一系列http請求,試想,如果這個網(wǎng)站的pv達到上百萬甚至上千萬,會對網(wǎng)站的后臺服務器造成多大的壓力。為了盡可能提升網(wǎng)站的性能,http協(xié)議給出了一個優(yōu)化方案:


image.png

上圖是當用戶第一次請求一個資源時的時序圖,瀏覽器會先詢問是否有命中緩存(第一次請求肯定是沒緩存啦),沒有命中的緩存則瀏覽器再從服務器獲取資源并將資源放進緩存?zhèn)}庫中,下次則可以從緩存中拿資源了。為方便理解,我們認為瀏覽器提供了緩存數(shù)據(jù)庫,只要瀏覽器發(fā)現(xiàn)滿足了某些緩存規(guī)則,就可以直接從緩存數(shù)據(jù)庫中取出你需要的資源。

上述是一個簡單過程,但是事實上的緩存策略還要更復雜一點。簡單來說,http根據(jù)是否要向服務器發(fā)送請求將緩存規(guī)則分為了兩類:強緩存對比緩存(對比緩存也叫做協(xié)商緩存)。

強緩存

強緩存直接從緩存數(shù)據(jù)庫中取出資源,無需再發(fā)送請求到服務器上:


image.png

http中用來判斷是否命中強緩存的字段為ExpiresCache-Control,Cache-Control優(yōu)先級高于Expires。

1. Expires

注:expires字段是HTTP 1.0 時代的產(chǎn)物,現(xiàn)在的瀏覽器用的全都是HTTP 1.1了,所以這個字段的作用基本可以忽略 。

來看下某個網(wǎng)站的一次請求中的信息:


image.png

expires的值是一個絕對時間,可以看到上圖中的時間點:2019年5月30號08:04:42,這代表:這個資源在這個時間點之前都可以直接從緩存中獲取。

2. Cache-Control

仍舊是上面請求中響應頭信息:


image.png

cache-control中定義了 public 和 max-age=7200,這是一個相對時間(單位:秒),這里代表資源的緩存在這個請求之后的2小時內(nèi)都有效。

請求頭cache-control字段列表:

  • Cache-Control: max-age=<seconds>
  • Cache-Control: max-stale[=<seconds>]
  • Cache-Control: min-fresh=<seconds>
  • Cache-control: no-cache
  • Cache-control: no-store
  • Cache-control: no-transform
  • Cache-control: only-if-cached

響應頭cache-control字段列表:

  • Cache-control: must-revalidate
  • Cache-control: no-cache
  • Cache-control: no-store
  • Cache-control: no-transform
  • Cache-control: public
  • Cache-control: private
  • Cache-control: proxy-revalidate
  • Cache-control: max-age=<seconds>
  • Cache-control: s-maxage=<seconds>

cache-control常見字段的含義:

  • public
    表明響應可以被任何對象(包括:發(fā)送請求的客戶端,CDN等代理服務器,等等)緩存,即使是通常不可緩存的內(nèi)容(例如,該響應沒有max-age指令或Expires消息頭)。
  • private
    表明響應只能被單個用戶緩存,不能作為共享緩存(即代理服務器不能緩存它)。私有緩存可以緩存響應內(nèi)容。
  • no-cache
    可以在本地進行緩存,但每次發(fā)請求時,都要向服務器進行驗證,如果服務器允許,才能使用本地緩存(即:需要協(xié)商緩存)。
  • no-store
    禁止緩存客戶端請求或服務器響應的內(nèi)容,每次都須重新請求服務器拿內(nèi)容
  • max-age
    設置緩存存儲的最大周期,超過這個時間緩存被視為過期 (單位**:秒)

更詳細的cache-control字段含義請看 MDN

強緩存狀態(tài)碼

強緩存狀態(tài)碼為200,但查看chrome的network會發(fā)現(xiàn)狀態(tài)碼后面多了個注釋:


image.png

事實上,強緩存時,這個注釋會有兩種情況:

  • from memory cache
  • from disk cache

1. from memory cache:
緩存資源在內(nèi)存中,瀏覽器(或頁面標簽)關閉后內(nèi)存中的緩存就會被釋放,重新打開頁面取不到該緩存。

2. from disk cache
緩存資源在硬盤中,瀏覽器(或頁面標簽)關閉后硬盤中的緩存不會消失,下次進入頁面還能從硬盤中獲取。

通常的緩存策略,瀏覽器打開一個網(wǎng)頁,如果該網(wǎng)頁最近訪問過,那么資源可能會出現(xiàn)from disk cache,從硬盤中讀取緩存;:

image.png

如果此時刷新頁面,該資源會出現(xiàn)from memory cache,從內(nèi)存中讀取緩存。眾所周知,內(nèi)存永遠是最快的。

如果不想從強緩存中獲取資源,windows電腦可以通過ctrl + f5刷新頁面,mac os 可以通過shift + command + r刷新頁面,刷新后你可以看到資源不會出現(xiàn) from disk(or memory) cache了。

對比緩存

對比緩存是需要經(jīng)過服務器確認是否使用緩存的機制,其http狀態(tài)碼為304,意為not modified。其過程如下:

image.png

可以看到,雖然客戶端仍然發(fā)起了http請求服務器,但是服務器只做了標志對比來確認是否使用緩存,如果確認使用緩存,就不會再返回具體的資源了。這樣做雖然沒有減少請求數(shù)量,但是極大減小了請求負荷,可以明顯提升請求速度和減小網(wǎng)絡帶寬。

問題是,如何對比標志來確認是否使用緩存?這里主要涉及到兩種標志:

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

1. Last-Modified / If-Modified-Since

當瀏覽器第一次訪問一個資源的時候,服務器會在response header中返回一個Last-Modified,代表這個資源最后的修改時間,當瀏覽器再次訪問這個資源的時候,會在request header中帶上 If-Modified-Since,值為上次請求時服務器返回的 Last-Modified 的值,然后服務器根據(jù)資源上次修改的時間確認資源在這段期間內(nèi)是否更改過,如果沒有,則返回304,如果有,則返回200并返回最新的資源。


image.png

如上圖,客戶端給服務器的 If-Modified-Since 值和服務端給的Last-Modified的值相同,表示2018年6月21號02:48:50至今,這個資源都沒被修改過,所以瀏覽器可以從緩存中獲取。再看其請求負荷,為575B:

image.png

通過shift+command+r刷新看下其真實大小,為4.3KB:

image.png

2. Etag / If-None-Match
Etag / If-None-Match 與 Last-Modified / If-Modified-Since 的機制類似,不同的是,Etag是通過一個校驗碼來對比資源是否更改過的,而不是通過資源的修改時間。當一個資源修改時,其校驗碼也會更改。當瀏覽器請求資源時,服務器會返回一個Etag字段,然后瀏覽器下一次請求時,會帶上 If-None-Match ,值為上次服務器返回的Etag的值,服務器經(jīng)過校驗碼的對比后決定返回200或304。
看個例子:

image.png

上圖中request header中帶上了 If-None-Match,值為 5b506e03-25856,response header中返回了Etag,值也是 5b506e03-25856,證明文件沒有修改過可以從緩存中獲取。

你可能注意到 If-None-Match 的值中有個 W/ 前綴,這個其實不用去關心,這個是用來提示應該采用弱比較算法(其實是畫蛇添足,因為 If-None-Match 用且僅用這一算法)。

Etag和Last-Modified優(yōu)先級

Etag可以解決 Last-Modified 不太好處理的問題,Etag能更準確地控制緩存,因此,如果http請求中若同時出現(xiàn)Etag和Last-Modified,Etag的優(yōu)先級是高于 Last-Modified 的。具體地說,Last-Modified 有以下一些問題:

  • 一些文件也許會周期性的更改,但是他的內(nèi)容并不改變(僅僅改變的修改時間),這個時候我們并不希望客戶端認為這個文件被修改了,而重新GET;
  • 某些文件修改非常頻繁,比如在秒以下的時間內(nèi)進行修改,(比方說1s內(nèi)修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);
  • 某些服務器不能精確的得到文件的最后修改時間。

總結

網(wǎng)上有副HTTP緩存邏輯流程圖,可以很清楚地表明其緩存策略:


image.png

參考

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 網(wǎng)絡特有的延遲以及數(shù)據(jù)傳輸?shù)某杀荆萍s互聯(lián)網(wǎng)快速獲取Web資源。為此,HTTP協(xié)議引入緩存以空間換時間,使瀏覽器緩...
    大頭8086閱讀 3,195評論 2 12
  • 本文內(nèi)容大多參考《圖解HTTP》一書 一. 認識代理服務器 所以講緩存為什么要先扯代理服務器?別急,讓我們看一下一...
    流光號船長閱讀 2,100評論 0 10
  • 瀏覽器對于請求資源, 流程如圖所示: 可以看到瀏覽器的緩存機制分為兩個部分: 1、當前緩存是否過期? 2、服務器中...
    zhoulujun閱讀 1,289評論 0 3
  • 今天看奇舞團推了篇文章講緩存策略的,講的挺不錯,記錄一下。 原文地址就在下面。 總結: 緩存分為強緩存和協(xié)商緩存...
    NowhereToRun閱讀 4,975評論 1 7
  • 作者:滌生_Woo鏈接:http://www.itdecent.cn/p/6e9e4156ece3 本篇文章篇幅...
    Fi的學習筆記閱讀 1,830評論 0 4

友情鏈接更多精彩內(nèi)容