圖解HTTP快取

RyuGou發表於2019-04-07

用途

HTTP快取主要用在對一些實時性要求不高的靜態檔案進行的快取,往往都是存在瀏覽器端,防止這些“多餘”的請求重複的訪問伺服器,對伺服器造成壓力,從而提高網站的效能。

原理

現有兩端,瀏覽器C和伺服器端S。

這裡寫圖片描述

瀏覽器向伺服器傳送請求,獲取一個檔案f

這裡寫圖片描述

伺服器就把f給返回瀏覽器

這裡寫圖片描述

假如這個檔案的內容變化不是那麼快,一兩週更新一次,瀏覽器每次請求伺服器都返回相同的檔案,豈不是對伺服器資源的一種浪費?

如何解決呢?

瀏覽器把請求後拿到的檔案存到本地,等下次請求的時候,看看本地是否有快取檔案,如果有,直接拿本地的檔案,豈不是就不用請求伺服器了?這其實就是http快取的最最根本的原理。

C端瀏覽器端把請求來的檔案快取到如圖下f的小方格內

這裡寫圖片描述

等到下次C端再次請求此檔案時,就直接從瀏覽器快取的檔案中拿,而不再向S伺服器端發起請求了

這裡寫圖片描述

以下瀏覽器截圖中標紅的部分,就是沒有發起請求,直接從瀏覽器快取中獲取的資料

這裡寫圖片描述

兩種快取方式

瀏覽器端有了快取之後,不能一直有效吧,如果檔案更新了,我們還繼續使用瀏覽器快取中的資料,雖說時效性不強,但長期使用舊檔案也不算合理吧。

http協議提供了兩種維度來讓快取失效:時間和檔案的修改。

利用時間來讓快取失效

時間維度很簡單,就是設定一個快取時間段,過了這個時間段,快取就自動失效了,瀏覽器就會發起請求獲取檔案。這個設定時間的http欄位就是cache-control欄位。

cache-control 可設定的欄位值有:

  • private :客戶端可以快取
  • public :客戶端和代理伺服器都可快取,大部分情況可以認為public和private是一樣的
  • max-age=xxx : 快取的內容將在 xxx 秒後失效 (時間就是在這兒設定的)
  • no-cache :需要使用另外一種http快取策略來驗證快取資料
  • no-store :所有快取策略都不會進行(這裡指的是兩種快取策略都不會進行)

cache-control 快取原理

第一次訪問請求,客戶端C向服務端S發起一個檔案請求,伺服器返回檔案並在response中加了響應頭"Cache-Control:max-age=60",這樣一來,這個f檔案只能在瀏覽器端存 60秒

這裡寫圖片描述

在這60秒鐘,客戶端請求伺服器的f檔案會直接從快取中拿取

這裡寫圖片描述

60秒過後,快取失效,瀏覽器再次請求檔案需要重新向伺服器發起請求。

這裡寫圖片描述

注意:假如說請求中包含“Cache-Control:max-age=0”或者“Cache-Control:no-store”無論響應中返回的"max-age"值是多少,都不會快取到伺服器。瀏覽器中對於位址列中直接輸入檔案地址的請求做了優化處理,加上了“Cache-Control:max-age=0”,也就是說,如果這個css、js或者其他靜態檔案是通過你在瀏覽器上直接輸入獲得的,將會每時每刻都是獲取最新的。

通過檢視檔案的修改來讓快取失效

這種維度比較的科學:瀏覽器先請求服務獲得檔案後,伺服器會返回該檔案的最後修改時間Last-Modified,作為檔案的一個標識,下次瀏覽器請求的時候,會帶著這個標識去請求(此時為If-Modified-Since),然後伺服器做校驗,如果說時間標識If-Modified-Since等於伺服器的檔案修改時間,則說明沒有修改,返回304狀態碼,瀏覽器從快取中獲取檔案,但是如果瀏覽器儲存的時間標識If-Modified-Since小於伺服器端的檔案修改時間,那麼,說明檔案發生了修改,瀏覽器就會重新獲取新的檔案。 (If-Modified-Since的時間如果大於伺服器端檔案的時間,會被認為是錯誤的請求)

如圖,瀏覽器C向伺服器發S起請求,伺服器S返回檔案的同時還會返回檔案的最後修改時間Last-Modified作為檔案時間標識,瀏覽器會將檔案和檔案時間標識都快取起來。

這裡寫圖片描述

假如伺服器端的檔案f並沒有被修改,伺服器通過判斷請求頭帶的時間標識If-Modified-Since得出結論後,都會返回狀態碼304告訴瀏覽器檔案沒有被修改,讓瀏覽器使用快取。

這裡寫圖片描述

假如伺服器端的檔案f修改了,那麼,瀏覽器將重新獲取檔案,並快取到瀏覽器中。

這裡寫圖片描述

雖然通過檔案最後修改時間作為標識已經很完美了,但是,還是可能存在一個問題:就是有可能伺服器端的檔案修改後,又改回原來的樣子,這樣,雖然檔案最後修改時間變了,但是,檔案內容並沒有改變。這樣還是會有多餘的請求到達伺服器,該如何處理呢? 可以將檔案內容作為一個唯一標識,例如可以對檔案內容取MD5值作為欄位(etag)也傳給瀏覽器端,假如這個檔案內容沒變化,那麼MD5值也不會改變。那麼,處理流程就變成了這樣:伺服器端先判斷檔案修改時間是否發生了變化,如果發生了變化,那麼再對比瀏覽器傳來的If-None-Match即瀏覽器端保留的E-tag值,如果發生了變化,則證明檔案修改了,需要瀏覽器重新下載檔案,如果沒有,則證明檔案內容沒變化,返回304狀態碼。

如圖,瀏覽器C要訪問伺服器S的f檔案,伺服器S返回了檔案最後修改時間Last-Modified和檔案的內容標識E-tag,瀏覽器將這兩個欄位及其檔案快取了起來

這裡寫圖片描述

當檔案最後修改時間沒變,檔案內容也沒變的時候,返回304,讓瀏覽器從快取中拿取檔案。

這裡寫圖片描述

當檔案最後修改時間變了,檔案內容沒變的時候,返回304,讓瀏覽器從快取中拿取檔案。

這裡寫圖片描述

當檔案修改時間變了,檔案內容也變了的時候,伺服器會重新下發新的檔案給瀏覽器。

這裡寫圖片描述

此維度讓快取失效牽扯的http欄位有點多,我們最後整理一下: 檔案最後修改時間欄位:

  • Response:Last-Modified
  • Request:If-Modified-Since

檔案內容標識欄位:

  • Response:E-tag
  • Request:If-None-Match

更多精彩內容,請關注我的微信公眾號 網際網路技術窩 或者加微信共同探討交流:

圖解HTTP快取

相關文章