自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

淺談瀏覽器緩存機(jī)制

開(kāi)發(fā) 前端
緩存一直是前端優(yōu)化的主戰(zhàn)場(chǎng), 利用好緩存就成功了一半. 本篇從http請(qǐng)求和響應(yīng)的頭域入手, 讓你對(duì)瀏覽器緩存有個(gè)整體的概念. 最終你會(huì)發(fā)現(xiàn)強(qiáng)緩存, 協(xié)商緩存 和 啟發(fā)式緩存是如此的簡(jiǎn)單.

緩存一直是前端優(yōu)化的主戰(zhàn)場(chǎng), 利用好緩存就成功了一半. 本篇從http請(qǐng)求和響應(yīng)的頭域入手, 讓你對(duì)瀏覽器緩存有個(gè)整體的概念. 最終你會(huì)發(fā)現(xiàn)強(qiáng)緩存, 協(xié)商緩存 和 啟發(fā)式緩存是如此的簡(jiǎn)單.

導(dǎo)讀

我不知道拖延癥是有多嚴(yán)重, 反正去年3月開(kāi)的題, 直到今年4月才開(kāi)始寫(xiě).(請(qǐng)盡情吐槽吧)

瀏覽器對(duì)于請(qǐng)求資源, 擁有一系列成熟的緩存策略. 按照發(fā)生的時(shí)間順序分別為存儲(chǔ)策略, 過(guò)期策略, 協(xié)商策略, 其中存儲(chǔ)策略在收到響應(yīng)后應(yīng)用, 過(guò)期策略, 協(xié)商策略在發(fā)送請(qǐng)求前應(yīng)用. 流程圖如下所示. 

流程圖 

廢話不多說(shuō), 我們先來(lái)看兩張表格.

1.http header中與緩存有關(guān)的key。

key 描述 存儲(chǔ)策略 過(guò)期策略 協(xié)商策略
Cache-Control 指定緩存機(jī)制,覆蓋其它設(shè)置  
Pragma http1.0字段,指定緩存機(jī)制    
Expires http1.0字段,指定緩存的過(guò)期時(shí)間    
Last-Modified 資源***一次的修改時(shí)間    
ETag 唯一標(biāo)識(shí)請(qǐng)求資源的字符串    

2.緩存協(xié)商策略用于重新驗(yàn)證緩存資源是否有效, 有關(guān)的key如下。

key 描述
If-Modified-Since 緩存校驗(yàn)字段, 值為資源***一次的修改時(shí)間, 即上次收到的Last-Modified值
If-Unmodified-Since 同上, 處理方式與之相反
If-Match 緩存校驗(yàn)字段, 值為唯一標(biāo)識(shí)請(qǐng)求資源的字符串, 即上次收到的ETag值
If-None-Match 同上, 處理方式與之相反

下面我們來(lái)看下各個(gè)頭域(key)的作用.

Cache-Control

瀏覽器緩存里, Cache-Control是金字塔***的規(guī)則, 它藐視一切其他設(shè)置, 只要其他設(shè)置與其抵觸, 一律覆蓋之.

不僅如此, 它還是一個(gè)復(fù)合規(guī)則, 包含多種值, 橫跨 存儲(chǔ)策略, 過(guò)期策略 兩種, 同時(shí)在請(qǐng)求頭和響應(yīng)頭都可設(shè)置.

語(yǔ)法為: “Cache-Control : cache-directive”. 

 

 

 

假設(shè)所請(qǐng)求資源于4月5日緩存, 且在4月12日過(guò)期.

當(dāng)max-age 與 max-stale 和 min-fresh 同時(shí)使用時(shí), 它們的設(shè)置相互之間獨(dú)立生效, 最為保守的緩存策略總是有效. 這意味著, 如果max-age=10 days, max-stale=2 days, min-fresh=3 days, 那么:

  • 根據(jù)max-age的設(shè)置, 覆蓋原緩存周期, 緩存資源將在4月15日失效(5+10=15);
  • 根據(jù)max-stale的設(shè)置, 緩存過(guò)期后兩天依然有效, 此時(shí)響應(yīng)將返回110(Response is stale)狀態(tài)碼, 緩存資源將在4月14日失效(12+2=14);
  • 根據(jù)min-fresh的設(shè)置, 至少要留有3天的新鮮期, 緩存資源將在4月9日失效(12-3=9);

由于客戶端總是采用最保守的緩存策略, 因此, 4月9日后, 對(duì)于該資源的請(qǐng)求將重新向服務(wù)器發(fā)起驗(yàn)證.

Pragma

http1.0字段, 通常設(shè)置為Pragma:no-cache, 作用同Cache-Control:no-cache. 當(dāng)一個(gè)no-cache請(qǐng)求發(fā)送給一個(gè)不遵循HTTP/1.1的服務(wù)器時(shí), 客戶端應(yīng)該包含pragma指令. 為此, 勾選☑ 上disable cache時(shí), 瀏覽器自動(dòng)帶上了pragma字段. 如下: 

 

 

 

Expires

  1. Expires:Wed, 05 Apr 2017 00:55:35 GMT 

即到期時(shí)間, 以服務(wù)器時(shí)間為參考系, 其優(yōu)先級(jí)比 Cache-Control:max-age 低, 兩者同時(shí)出現(xiàn)在響應(yīng)頭時(shí), Expires將被后者覆蓋. 如果Expires, Cache-Control: max-age, 或 Cache-Control:s-maxage 都沒(méi)有在響應(yīng)頭中出現(xiàn), 并且也沒(méi)有其它緩存的設(shè)置, 那么瀏覽器默認(rèn)會(huì)采用一個(gè)啟發(fā)式的算法, 通常會(huì)取響應(yīng)頭的Date_value - Last-Modified_value值的10%作為緩存時(shí)間.

如下資源便采取了啟發(fā)式緩存算法. 

 

 

 

其緩存時(shí)間為 (Date_value - Last-Modified_value) * 10%, 計(jì)算如下:

  1. const Date_value = new Date('Thu, 06 Apr 2017 01:30:56 GMT').getTime(); 
  2.  
  3. const LastModified_value = new Date('Thu, 01 Dec 2016 06:23:23 GMT').getTime(); 
  4.  
  5. const cacheTime = (Date_value - LastModified_value) / 10; 
  6.  
  7. const Expires_timestamp = Date_value + cacheTime; 
  8.  
  9. const Expires_value = new Date(Expires_timestamp); 
  10.  
  11. console.log('Expires:', Expires_value); // Expires: Tue Apr 18 2017 23:25:41 GMT+0800 (CST)  

可見(jiàn)該資源將于2017年4月18日23點(diǎn)25分41秒過(guò)期, 嘗試以下兩步進(jìn)行驗(yàn)證:

1) 試著把本地時(shí)間修改為2017年4月18日23點(diǎn)25分40秒, 迅速刷新頁(yè)面, 發(fā)現(xiàn)強(qiáng)緩存依然有效(依舊是200 OK (from disk cache)).

2) 然后又修改本地時(shí)間為2017年4月18日23點(diǎn)26分40秒(即往后撥1分鐘), 刷新頁(yè)面, 發(fā)現(xiàn)緩存已過(guò)期, 此時(shí)瀏覽器重新向服務(wù)器發(fā)起了驗(yàn)證, 且***了304協(xié)商緩存, 如下所示. 

 

 

 

3) 將本地時(shí)間恢復(fù)正常(即 2017-04-06 09:54:19). 刷新頁(yè)面, 發(fā)現(xiàn)Date依然是4月18日, 如下所示. 

 

 

從⚠ Provisional headers are shown 和Date字段可以看出來(lái), 瀏覽器并未發(fā)出請(qǐng)求, 緩存依然有效, 只不過(guò)此時(shí)Status Code顯示為200 OK. (甚至我還專門(mén)打開(kāi)了charles, 也沒(méi)有發(fā)現(xiàn)該資源的任何請(qǐng)求, 可見(jiàn)這個(gè)200 OK多少有些誤導(dǎo)人的意味)

可見(jiàn), 啟發(fā)式緩存算法采用的緩存時(shí)間可長(zhǎng)可短, 因此對(duì)于常規(guī)資源, 建議明確設(shè)置緩存時(shí)間(如指定max-age 或 expires).

ETag

  1. ETag:"fcb82312d92970bdf0d18a4eca08ebc7efede4fe" 

實(shí)體標(biāo)簽, 服務(wù)器資源的唯一標(biāo)識(shí)符, 瀏覽器可以根據(jù)ETag值緩存數(shù)據(jù), 節(jié)省帶寬. 如果資源已經(jīng)改變, etag可以幫助防止同步更新資源的相互覆蓋. ETag 優(yōu)先級(jí)比 Last-Modified 高.

If-Match

語(yǔ)法: If-Match: ETag_value 或者 If-Match: ETag_value, ETag_value, …

緩存校驗(yàn)字段, 其值為上次收到的一個(gè)或多個(gè)etag 值. 常用于判斷條件是否滿足, 如下兩種場(chǎng)景:

  • 對(duì)于 GET 或 HEAD 請(qǐng)求, 結(jié)合 Range 頭字段, 它可以保證新范圍的請(qǐng)求和前一個(gè)來(lái)自相同的源, 如果不匹配, 服務(wù)器將返回一個(gè)416(Range Not Satisfiable)狀態(tài)碼的響應(yīng).
  • 對(duì)于 PUT 或者其他不安全的請(qǐng)求, If-Match 可用于阻止錯(cuò)誤的更新操作, 如果不匹配, 服務(wù)器將返回一個(gè)412(Precondition Failed)狀態(tài)碼的響應(yīng).

If-None-Match

語(yǔ)法: If-None-Match: ETag_value 或者 If-None-Match: ETag_value, ETag_value, …

緩存校驗(yàn)字段, 結(jié)合ETag字段, 常用于判斷緩存資源是否有效, 優(yōu)先級(jí)比If-Modified-Since高.

  • 對(duì)于 GET 或 HEAD 請(qǐng)求, 如果其etags列表均不匹配, 服務(wù)器將返回200狀態(tài)碼的響應(yīng), 反之, 將返回304(Not Modified)狀態(tài)碼的響應(yīng). 無(wú)論是200還是304響應(yīng), 都至少返回 Cache-Control, Content-Location, Date, ETag, Expires, and Vary 中之一的字段.
  • 對(duì)于其他更新服務(wù)器資源的請(qǐng)求, 如果其etags列表匹配, 服務(wù)器將執(zhí)行更新, 反之, 將返回412(Precondition Failed)狀態(tài)碼的響應(yīng).

Last-Modified

語(yǔ)法: Last-Modified: 星期,日期 月份 年份 時(shí):分:秒 GMT

  1. Last-Modified: Tue, 04 Apr 2017 10:01:15 GMT 

用于標(biāo)記請(qǐng)求資源的***一次修改時(shí)間, 格式為GMT(格林尼治標(biāo)準(zhǔn)時(shí)間). 如可用 new Date().toGMTString()獲取當(dāng)前GMT時(shí)間. Last-Modified 是 ETag 的fallback機(jī)制, 優(yōu)先級(jí)比 ETag 低, 且只能精確到秒, 因此不太適合短時(shí)間內(nèi)頻繁改動(dòng)的資源. 不僅如此, 服務(wù)器端的靜態(tài)資源, 通常需要編譯打包, 可能出現(xiàn)資源內(nèi)容沒(méi)有改變, 而Last-Modified卻改變的情況.

If-Modified-Since

語(yǔ)法同上, 如:

  1. If-Modified-Since: Tue, 04 Apr 2017 10:12:27 GMT 

緩存校驗(yàn)字段, 其值為上次響應(yīng)頭的Last-Modified值, 若與請(qǐng)求資源當(dāng)前的Last-Modified值相同, 那么將返回304狀態(tài)碼的響應(yīng), 反之, 將返回200狀態(tài)碼響應(yīng).

If-Unmodified-Since

緩存校驗(yàn)字段, 語(yǔ)法同上. 表示資源未修改則正常執(zhí)行更新, 否則返回412(Precondition Failed)狀態(tài)碼的響應(yīng). 常用于如下兩種場(chǎng)景:

  • 不安全的請(qǐng)求, 比如說(shuō)使用post請(qǐng)求更新wiki文檔, 文檔未修改時(shí)才執(zhí)行更新.
  • 與 If-Range 字段同時(shí)使用時(shí), 可以用來(lái)保證新的片段請(qǐng)求來(lái)自一個(gè)未修改的文檔.

強(qiáng)緩存

一旦資源***強(qiáng)緩存, 瀏覽器便不會(huì)向服務(wù)器發(fā)送請(qǐng)求, 而是直接讀取緩存. Chrome下的現(xiàn)象是 200 OK (from disk cache) 或者 200 OK (from memory cache). 如下: 

 

 

   

對(duì)于常規(guī)請(qǐng)求, 只要存在該資源的緩存, 且Cache-Control:max-age 或者expires沒(méi)有過(guò)期, 那么就能***強(qiáng)緩存.

協(xié)商緩存

緩存過(guò)期后, 繼續(xù)請(qǐng)求該資源, 對(duì)于現(xiàn)代瀏覽器, 擁有如下兩種做法:

  • 根據(jù)上次響應(yīng)中的ETag_value, 自動(dòng)往request header中添加If-None-Match字段. 服務(wù)器收到請(qǐng)求后, 拿If-None-Match字段的值與資源的ETag值進(jìn)行比較, 若相同, 則***協(xié)商緩存, 返回304響應(yīng).
  • 根據(jù)上次響應(yīng)中的Last-Modified_value, 自動(dòng)往request header中添加If-Modified-Since字段. 服務(wù)器收到請(qǐng)求后, 拿If-Modified-Since字段的值與資源的Last-Modified值進(jìn)行比較, 若相同, 則***協(xié)商緩存, 返回304響應(yīng).

以上, ETag優(yōu)先級(jí)比Last-Modified高, 同時(shí)存在時(shí), 前者覆蓋后者. 下面通過(guò)實(shí)例來(lái)理解下強(qiáng)緩存和協(xié)商緩存.

如下忽略***訪問(wèn), 第二次通過(guò) If-Modified-Since ***了304協(xié)商緩存. 

 

 

 

協(xié)商緩存的響應(yīng)結(jié)果, 不僅驗(yàn)證了資源的有效性, 同時(shí)還更新了瀏覽器緩存. 主要更新內(nèi)容如下:

  1. Age:0 
  2.  
  3. Cache-Control:max-age=600 
  4.  
  5. Date: Wed, 05 Apr 2017 13:09:36 GMT 
  6.  
  7. Expires:Wed, 05 Apr 2017 00:55:35 GMT  

Age:0 表示***了代理服務(wù)器的緩存, age值為0表示代理服務(wù)器剛剛刷新了一次緩存.

Cache-Control:max-age=600 覆蓋 Expires 字段, 表示從Date_value, 即 Wed, 0***pr 2017 13:09:36 GMT 起, 10分鐘之后緩存過(guò)期. 因此10分鐘之內(nèi)訪問(wèn), 將會(huì)***強(qiáng)緩存, 如下所示: 

 

 

當(dāng)然, 除了上述與緩存直接相關(guān)的字段外, http header中還包括如下間接相關(guān)的字段.

Age

出現(xiàn)此字段, 表示***代理服務(wù)器的緩存. 它指的是代理服務(wù)器對(duì)于請(qǐng)求資源的已緩存時(shí)間, 單位為秒. 如下:

  1. Age:2383321 
  2.  
  3. Date:Wed, 08 Mar 2017 16:12:42 GMT  

以上指的是, 代理服務(wù)器在2017年3月8日16:12:42時(shí)向源服務(wù)器發(fā)起了對(duì)該資源的請(qǐng)求, 目前已緩存了該資源2383321秒.

Date

指的是響應(yīng)生成的時(shí)間. 請(qǐng)求經(jīng)過(guò)代理服務(wù)器時(shí), 返回的Date未必是***的, 通常這個(gè)時(shí)候, 代理服務(wù)器將增加一個(gè)Age字段告知該資源已緩存了多久.

Vary

對(duì)于服務(wù)器而言, 資源文件可能不止一個(gè)版本, 比如說(shuō)壓縮和未壓縮, 針對(duì)不同的客戶端, 通常需要返回不同的資源版本. 比如說(shuō)老式的瀏覽器可能不支持解壓縮, 這個(gè)時(shí)候, 就需要返回一個(gè)未壓縮的版本; 對(duì)于新的瀏覽器, 支持壓縮, 返回一個(gè)壓縮的版本, 有利于節(jié)省帶寬, 提升體驗(yàn). 那么怎么區(qū)分這個(gè)版本呢, 這個(gè)時(shí)候就需要Vary了.

服務(wù)器通過(guò)指定Vary: Accept-Encoding, 告知代理服務(wù)器, 對(duì)于這個(gè)資源, 需要緩存兩個(gè)版本: 壓縮和未壓縮. 這樣老式瀏覽器和新的瀏覽器, 通過(guò)代理, 就分別拿到了未壓縮和壓縮版本的資源, 避免了都拿同一個(gè)資源的尷尬.

  1. Vary:Accept-Encoding,User-Agent 

如上設(shè)置, 代理服務(wù)器將針對(duì)是否壓縮和瀏覽器類(lèi)型兩個(gè)維度去緩存資源. 如此一來(lái), 同一個(gè)url, 就能針對(duì)PC和Mobile返回不同的緩存內(nèi)容.

怎么讓瀏覽器不緩存靜態(tài)資源

實(shí)際上, 工作中很多場(chǎng)景都需要避免瀏覽器緩存, 除了瀏覽器隱私模式, 請(qǐng)求時(shí)想要禁用緩存, 還可以設(shè)置請(qǐng)求頭: Cache-Control: no-cache, no-store, must-revalidate .

當(dāng)然, 還有一種常用做法: 即給請(qǐng)求的資源增加一個(gè)版本號(hào), 如下:

  1. <link rel="stylesheet" type="text/css" href="../css/style.css?version=1.8.9"/> 

這樣做的好處就是你可以自由控制什么時(shí)候加載***的資源.

不僅如此, HTML也可以禁用緩存, 即在頁(yè)面的

節(jié)點(diǎn)中加入標(biāo)簽, 代碼如下:

  1. <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"/> 

上述雖能禁用緩存, 但只有部分瀏覽器支持, 而且由于代理不解析HTML文檔, 故代理服務(wù)器也不支持這種方式.

IE8的異常表現(xiàn)

實(shí)際上, 上述緩存有關(guān)的規(guī)律, 并非所有瀏覽器都完全遵循. 比如說(shuō)IE8.

資源緩存是否有效相關(guān).

瀏覽器 前提 操作 表現(xiàn) 正常表現(xiàn)
IE8 資源緩存有效 新開(kāi)一個(gè)窗口加載網(wǎng)頁(yè) 重新發(fā)送請(qǐng)求(返回200) 展示緩存的頁(yè)面
IE8 資源緩存失效 原瀏覽器窗口中單擊 Enter 按鈕 展示緩存的頁(yè)面 重新發(fā)送請(qǐng)求(返回200)

Last-Modified / E-Tag 相關(guān).

瀏覽器 前提 操作 表現(xiàn) 正常表現(xiàn)
IE8 資源內(nèi)容沒(méi)有修改 新開(kāi)一個(gè)窗口加載網(wǎng)頁(yè) 瀏覽器重新發(fā)送請(qǐng)求(返回200) 重新發(fā)送請(qǐng)求(返回304)
IE8 資源內(nèi)容已修改 原瀏覽器窗口中單擊 Enter 按鈕 瀏覽器展示緩存的頁(yè)面 重新發(fā)送請(qǐng)求(返回200)

參考文章

  • Cache Policy Interaction—Maximum Age and Maximum Staleness
  • HTTP/1.1: Header Field Definitions
  • http – What’s the difference between Cache-Control: max-age=0 and no-cache? – Stack Overflow
  • App 緩存方案:Http 緩存 · baitouwei
  • Cache-Control – HTTP | MDN
  • 徹底弄懂 Http 緩存機(jī)制 – 基于緩存策略三要素分解法 
責(zé)任編輯:龐桂玉 來(lái)源: 前端大全
相關(guān)推薦

2017-05-15 13:40:20

瀏覽器http緩存機(jī)制

2018-08-07 10:44:50

緩存技術(shù)瀏覽器

2020-03-11 20:42:34

瀏覽器緩存機(jī)制

2021-07-22 09:55:28

瀏覽器前端緩存

2016-01-05 12:54:52

瀏覽器瀏覽器端緩存

2017-09-28 12:03:40

前端

2017-05-19 08:05:08

瀏覽器緩存HTTP

2019-01-03 13:09:58

瀏覽器緩存原理

2009-06-22 14:06:00

java瀏覽器

2017-05-02 09:25:13

瀏覽器指紋追蹤虛擬化

2011-06-10 16:44:17

Qt 瀏覽器

2011-05-06 09:36:16

動(dòng)態(tài)頁(yè)面

2021-06-01 09:12:47

前端瀏覽器緩存

2020-07-16 08:04:21

瀏覽器緩存策略

2021-08-02 13:05:49

瀏覽器HTTP前端

2020-11-30 07:02:43

瀏覽器緩存機(jī)制

2020-12-29 09:56:29

瀏覽器緩存HTTP

2020-10-29 11:04:28

緩存瀏覽器LocalStorag

2018-11-30 09:00:19

html5cssjavascript

2013-07-08 14:45:52

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)