HTTP快取機制及原理

舞動乾坤發表於2019-03-31

一、前言

       上週阿里的面試官問了個面試題 “ 能不能說下 304 的過程,以及影響快取的頭部屬性有哪些?”OMG.......因為之前只是大概瞭解 304 狀態碼是表示快取,且因為平時專案開發過程中也沒有在快取這塊踩過坑,所以這一塊也沒有去做特別深入的研究。所以當被問這個問題時,有被當頭一棒的感覺,也好好反思了下,自己校招以軟體開發工程師的職位進入公司,之前沒有想過要從事前端開發,所以前端基礎幾乎可以忽略不計。工作一年多來,為在工作上表現突出,在工作上投入大量的精力,幹到晚上10點是常規操作,週末至少加班1天;並且空餘時間,經常看前端相關書籍彌補基礎,如《JavaScript 高階程式設計》、《CSS 權威指南》、《Sass 實踐》、《JavaScript 高效能程式設計》....《Webpack 實踐》、《深入淺出 node.js》等不下10本書;在廣度上涉及的還是很多的,但是存在問題:從事前端時間不長,前端知識雜而多,如果沒有專門準備,如果突然問你一個知識點,你雖然大概知道這是啥,但是讓你講的話,你很難有條理的講清楚。
       So,下一階段的首要任務:“打好打牢前端基礎,深入瞭解所用的技術棧原理”。廢話少說,學問學問,不懂就弄清楚!以下“理論知識 + 實踐操作”來徹底弄懂 HTTP 快取機制及原理!

二、快取規則及解析

       為方便大家理解,我假設覽器存在一個快取資料庫,用於儲存快取資訊。在客戶端第一次請求資料時,此時快取資料庫中沒有對應的快取資料,需要請求伺服器,伺服器返回後,將資料儲存至快取資料庫中。如下流程圖所示:
HTTP快取機制及原理
       根據是否需要重新向伺服器發起請求來分類,將HTTP快取規則分為兩大類(強制快取對比快取)在詳細介紹這兩種規則之前,先通過時序圖的方式,讓大家對這兩種規則有個簡單瞭解。
(1)已存在快取資料時,僅基於強制快取,請求資料的流程如下所示:

HTTP快取機制及原理

(2)已存在快取資料時,僅基於對比快取,請求資料的流程如下所示:

HTTP快取機制及原理

       我們可以看到兩類快取規則的不同,強制快取如果生效,不需要再和伺服器發生互動,而對比快取不管是否生效,都需要與服務端發生互動。
       兩類快取規則可以同時存在,強制快取優先順序高於對比快取,也就是說,當執行強制快取的規則時,如果快取生效,直接使用快取,不再執行對比快取規則。

三、快取常用欄位

1、http1.0時期的快取方案

HTTP快取機制及原理

注意: 

(1)如果使用了Pragma: 'no-cache'的話,再設定Expires或者Cache-Control,就沒有用了,說明Pragma的權值比後兩者高。

 (2)如果設定了Expires之後,客戶端在需要請求資料的時候,首先會對比當前系統時間和這個Expires時間,如果沒有超過Expires時間,則直接讀取本地磁碟中的快取資料,不傳送請求。

2、http1.1 時期的快取方案

2.1、Cache-Control 欄位 

2.1.1、Cache-Control 作為請求頭欄位

HTTP快取機制及原理

(1)Cache-Control: no-cache 

使用no-cache指令的目的是為了防止從快取中返回過期的資源。 客戶端傳送的請求中如果包含 no-cache 指令,則表示客戶端將不會接收快取的資源。每次請求都是從伺服器獲取資源,返回304。  

(2)Cache-Control: no-store 

使用no-store 指令表示請求的資源不會被快取,下次任何其它請求獲取該資源,還是會從伺服器獲取,返回 200,即資源本身。

2.1.2、Cache-Control 作為響應頭欄位

HTTP快取機制及原理

Cache-Control: public 

當指定使用 public 指令時,則明確表明其他使用者也可利用快取。

 Cache-Control: private

當指定 private 指令後,響應只以特定的使用者作為物件,這與 public 指令的行為相反。 快取伺服器會對該特定使用者提供資源快取的服務,對於其他使用者傳送 過來的請求,代理伺服器則不會返回快取。

 Cache-Control: no-cache 

如果伺服器返回的響應中包含 no-cache 指令,每次客戶端請求,必需先向伺服器確認其有效性,如果資源沒有更改,則返回304. 

Cache-Control: no-store 

不對響應的資源進行快取,即使用者下次請求還是返回 200,返回資源本身。 

Cache-Control: max-age=604800(單位:秒) 

資源快取在本地瀏覽器的時間,如果超過該時間,則重新向伺服器獲取。

2.2、請求頭部欄位 & 響應頭部欄位

2.2.1、請求頭部欄位

HTTP快取機制及原理

2.2.2、響應頭部欄位

HTTP快取機制及原理

注意:

 (1)If-None-Match的優先順序比If-Modified-Since高,所以兩者同時存在時,遵從前者。

四、實驗驗證

1、實驗1 — 請求的資源沒修改,驗證2種快取出現的情形
服務端使用 node.js , 客戶端使用 axios 進行請求:
1.1、請求頭部 / 響應頭部 設定
(1)服務端響應頭部設定:
     res.setHeader('Cache-Control', 'public, max-age=10');
(2)客戶端請求頭部使用預設設定

1.2、實驗步驟
(1)請求 3 次,第一次請求請求資源;第二次在10秒內再次請求該資源,第三次在 10 秒後再次請求該資源(實驗過程中,服務端的資源沒有進行改變)

1.3、實驗結果
      3 次請求的 HTTP 資訊如下圖所示,從圖中的資訊可以得出,第一次請求該資源是從伺服器獲取;第二次(10 秒內)請求該資源是直接從瀏覽器快取中獲取該資源(沒有向伺服器確認);第三次(10 秒後)請求該資源時,因為資源快取時間(10 秒)過期,所以向伺服器獲取資源,伺服器判斷該資源與本地快取的資源沒有做更改,所以返回 304,讓客戶端直接從瀏覽器快取中獲取該資源;以下,根據 HTTP 頭部資訊詳細介紹三個操作的互動過程。

HTTP快取機制及原理

1.3.1、第一次請求資源
第一次請求資源的請求頭部和響應頭部的截圖如下所示,因為第一次請求該資源,本地並沒有快取,所以直接從伺服器獲取該資源;我們從截圖可以看到,伺服器返回改資源的響應頭部中包含3個屬性與資源快取相關:
(1)cache-control: public, max-age=10
快取規則的設定,我們這個示例中,設定快取規則為 public, 並且設定快取過期時間為10秒;
(2)etag: W/"95f15b-16994d7ebf6"
資源的唯一識別符號,客戶端下次訪問該資源時,會在請求頭中攜帶 etag 去向伺服器確認,該資源是否被修改;
(3)last-modified: Tue, 19 Mar 2019 07:26:12 GMT
資源最後一次修改時間,客戶端下次訪問該資源時,會在請求頭中攜帶該資訊去向伺服器進行匹配,該資源是否被修改;

HTTP快取機制及原理

1.3.2、第二次請求資源(10秒內,即在快取時間失效前)
       第二次請求資源的請求頭部和響應頭部的截圖如下所示,因為第二次請求該資源,該資源本地快取還沒失效,所以就直接從瀏覽器快取中獲取該資源。

HTTP快取機制及原理

1.3.3、第三次請求資源(10秒後,即在快取時間失效後)
       第三次請求資源的請求頭部和響應頭部的截圖如下所示,因為第三次請求該資源,該資源本地快取已經失效,所以在請求頭部中加入 If-Modified-Since If-None-Match 屬性,來向伺服器進行確認該資源是否有被更改。

HTTP快取機制及原理


2、實驗2 — 請求的資源進行修改,驗證2種快取出現的情形
服務端使用 node.js , 客戶端使用 axios 進行請求:
2.1、請求頭部 / 響應頭部 設定
(1)服務端響應頭部設定:
     res.setHeader('Cache-Control', 'public, max-age=20');
(2)客戶端請求頭部使用預設設定

2.2、實驗步驟
(1)請求 3 次,第一次請求資源;然後在伺服器對請求的資源進行修改,第二次在 20 秒內再次請求該資源,第三次在 20 秒後再次請求該資源

2.3、實驗結果
       3 次請求的 HTTP 資訊如下圖所示,從圖中的資訊可以得出,第一次請求該資源是從伺服器獲取;第二次(20 秒內)請求該資源是直接從瀏覽器快取中獲取該資源(沒有向伺服器確認);第三次(20 秒後)請求該資源時,因為資源快取時間(20 秒)過期,所以向伺服器獲取資源,伺服器判斷該資源與本地快取的資源不同,所以重新返回該資源;以下,根據 HTTP 頭部資訊詳細介紹三個操作的互動過程。

HTTP快取機制及原理

2.3.1、第一次請求資源
       第一次請求資源的請求頭部和響應頭部的截圖如下所示,具體詳細資訊與 1.3.1 小節相同,在此不同重複介紹。

HTTP快取機制及原理

2.3.2、第二次請求資源(20 秒內,即在快取時間失效前)
      第二次請求資源的請求頭部和響應頭部的截圖如下所示,(注意:即使此時伺服器上的資源已經更改,但是由於快取在瀏覽器中的資源沒有過期,所以還是從快取中返回舊資源)。

HTTP快取機制及原理

2.3.3、第三次請求資源(20 秒後,即在快取時間失效後)
       第三次請求資源的請求頭部和響應頭部的截圖如下所示,因為第三次請求該資源,該資源本地快取已經失效,所以在請求頭部中加入 If-Modified-Since If-None-Match 屬性,來向伺服器進行確認該資源是否有被更改,從下圖中可以看到,響應頭部的屬性 etag 與 請求頭部的屬性 If-None-Match 不同,響應頭部的屬性 If-Modified-Since 與 請求頭部的屬性 last-modified 不同;所以伺服器返回該資源的最新資源。

HTTP快取機制及原理

五、總結

1、對於強制快取,伺服器通知瀏覽器一個快取時間,在快取時間內,下次請求,直接用快取,不在時間內,執行比較快取策略。
2、對於比較快取,將快取資訊中的Etag和Last-Modified通過請求傳送給伺服器,由伺服器校驗,返回304狀態碼時,瀏覽器直接使用快取。
總結流程圖如下所示:

HTTP快取機制及原理



轉自深入理解HTTP快取機制及原理

相關文章