緩存相關字段:
http1.0:pragma、expires
http1.1:cache-control、last-modified、if-modified-since、etag、if-none-match
強緩存:
不發起http請求,直接使用本地緩存,比如瀏覽器地址欄回車,使用瀏覽器的刷新按鈕,在Expires或max-age生效的情況下,觸發強緩存。
不經常被修改的文件,通常用強緩存
協商緩存(弱緩存):
在使用本地緩存前,先與服務器協商,核對緩存文件是否為最新。請求頭攜帶If-None-Match或If-Modified-Since,也可都攜帶。
一、Cache-control請求頭/響應頭
1.客戶端設置
max-age:表示本地緩存的資源將在xx秒之后過期
no-cache:跳過強緩存和協商緩存階段,直接請求服務器
no-store:不在本地緩存數據。
2.服務端設置
max-age:讓客戶端在xx秒內,不發起請求,直接使用本地緩存。(max-age=0相當於no-cache)
s-maxage: 覆蓋max-age或者Expires頭,但是僅適用於共享緩存(比如各個代理),私有緩存會忽略它。
no-cache:強制瀏覽器重新發送請求,但瀏覽器會緩存到本地。(不使用緩存)
no-store: 強制瀏覽器重新發送請求,並且禁止瀏覽器緩存數據。(不緩存)
public:響應可以被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存
private:響應只能被單個用戶緩存,不能作為共享緩存(即代理服務器不能緩存它)。私有緩存可以緩存響應內容,比如:對應用戶的本地瀏覽器。
must-revalidate:一旦資源過期(比如已經超過max-age),在成功向原始服務器驗證之前,緩存不能用該資源響應后續請求。
immutable:響應正文不會隨時間而改變。資源未過期,客戶端不應發送重新驗證請求頭(例如If-None-Match或If-Modified-Since)來檢查更新,即使用戶顯式地刷新頁面。
二、Pragma 請求頭/響應頭
pragma:no-cache
http1.0使用的緩存字段,現在不常用,向后兼容只支持 HTTP/1.0 協議的緩存服務器,與 Cache-Control: no-cache 效果一致。
三、過期時間expires和cache-control:max-age
Expires: Thu, 29 Oct 2020 11:29:05 GMT 和 cache-control:max-age=10效果類似,max-age是相對時間,表示過了10s過后 再重新請求 而expires是絕對時間,表示過了這個時間,再重新請求。
1.首次請求
客戶端:請求a.js文件
服務器:返回a.js + cache-control:max-age=10 + 過期時間Expires(Expires: Thu, 29 Oct 2020 11:29:05 GMT)
注意:expires主要是用來兼容http1.0版本的瀏覽器
如果在Cache-Control響應頭設置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 頭會被忽略。
2.后續請求
客戶端:
(1)先判斷本地時間是否超過了過期時間,若時間沒過,不發起請求,直接使用本地緩存。
(2)時間過期,重復步驟1
問題:
假設已過期,瀏覽器再次請求服務器,但a.js相比上次並未做任何改變,那這次請求我們是否通過某種方式加以避免?
四、Last-Modified(響應頭)和if-Modified-Since(請求頭)
同時設置cache-control:max-age和 last-modified表示強制緩存和協商緩存共用,若cache-control設置為max-age=0或者no-cache,則只有協商緩存生效
1.首次請求
客戶端:請求a.js文件
服務器:返回a.js + cache-control:max-age=10 + last-modified(Thu, 22 Oct 2020 10:23:29 GMT) + 狀態碼200
2.后續請求
客戶端:
(1)先判斷本地時間是否超過了過期時間max-age,若未過期,使用瀏覽器緩存。
(2)過期,客戶端帶上if-Modified-Since(也就是上次請求服務器返回的Last-Modified),服務器將客戶端傳來的if-Modified-Since與自己的Last-Modified做對比。
(3)若if-Modified-Since ≠ Last-Modified,服務器返回新的a.js + 新的Last-Modified + cache-control:max-age=10
(4)若if-Modified-Since = Last-Modified,服務器返回狀態碼304,表示文件沒修改過,讓客戶端使用瀏覽器的緩存。
問題:
1.資源文件每次一被修改,Last-Modified也會跟着修改,如果修改過后又進行版本回退,內容跟瀏覽器已緩存的一致,但用戶還是要重新請求資源,因為Last-Modified改變了。
2.Last-Modified只能精確到秒,如果恰好在一秒之內變化了,Last-Modified是不會修改成功的。
五、Etag(響應頭)和if-None-Match(請求頭)
服務端生成資源文件的唯一標識符Etag,資源更改,則一定要生成新的Etag值
對於大文件,不會根據整個文件去生成hash 可以使用文件大小或者文件開頭去生成hash
md5是 摘要算法,也叫hash算法
1. 是單向的 無法反解
2. 對於相同內容 加密結果相同;不同的內容 加密結果的長度相同
1.首次請求
客戶端:請求a.js文件
服務器:返回a.js + cache-control:max-age=10 + last-modified(Thu, 22 Oct 2020 10:23:29 GMT) + Etag + 200
2.后續請求
客戶端:
(1)先判斷本地時間是否超過了過期時間max-age,未過期,則使用瀏覽器緩存。
(2)若過期,客戶端帶上if-Modified-Since + if-None-Match,服務器先將客戶端傳來的if-None-Match與自己的Etag做對比。
(3)若if-None-Match ≠ Etag 服務器返回新的a.js + 新的Etag + Last-Modified + cache-control:max-age=10
(4)若if-None-Match = Etag,服務器返回狀態碼304,表示文件沒修改過,讓客戶端使用瀏覽器的緩存,if-Modified-Since和Last-Modified 也不需要再比較了。
面試點睛:
1.為什么有了Last-Modified還要用etag?
- 防止Last-Modified變了,但文件內容沒變的情況下,瀏覽器需要重新請求服務器
- 防止文件在1s內發生變化,而Last-Modified不變
2.用戶行為如何觸發緩存?
- 打開網頁,地址欄輸入地址: 查找 disk cache 中是否有匹配。如有則使用;如沒有則發送網絡請求。
- 普通刷新 (F5):因為 TAB 並沒有關閉,因此 memory cache 是可用的,會被優先使用(如果匹配的話)。其次才是 disk cache。
- 強制刷新 (Ctrl + F5):瀏覽器不使用緩存,因此發送的請求頭部均帶有 Cache-control: no-cache(為了兼容,還帶了 Pragma: no-cache),服務器直接返回 200 和最新內容。
