用途
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