HTTP中的強緩存與協商緩存
HTTP中的強緩存與協商緩存
強緩存
在瀏覽器加載資源的時候,首先會根據請求頭的
expires和cache-control判斷是否命中強緩存策略,判斷是否向遠程服務器請求資源還是去本地獲取緩存資源。
Expires
Expires是http1.0的規范,用于表示資源的過期時間的請求頭字段,值是一個絕對時間,是由服務器端返回的。
在瀏覽器第一個請求資源時,服務器端的響應頭會附上
Expires這個響應字段,當瀏覽器在下一次請求這個資源時會根據上次的expires字段是否使用緩存資源(當請求時間小于服務端返回的到期時間,直接使用緩存數據)
expires是根據本地時間來判斷的,假設客戶端和服務器時間不同,會導致緩存命中誤差。
Cache-control
上面我們提到了
Expires有個缺點,當客戶端本地時間被修改時瀏覽器會直接向服務器請求新的資源,為了解決這個問題,在http1.1規范中,提出了cache-control字段,且這個字段優先級高于上面提到的Expires,值是相對時間。
在
cache-control中有常見的幾個響應屬性值,它們分別是
| 屬性值 | 值 | 備注 |
|---|---|---|
| max-age | 3600 | 例如值為3600,表示(當前時間+3600秒)內不與服務器請求新的數據資源 |
| s-maxage | 和max-age一樣,但這個是設定代理服務器的緩存時間 | |
| private | 內容只緩存到私有緩存中(僅客戶端可以緩存,代理服務器不可緩存) | |
| public | 所有內容都將被緩存(客戶端和代理服務器都可緩存) | |
| no-store | 不緩存任何數據 | |
| no-cache | 儲存在本地緩存區中,只是在與原始服務器進行新鮮度再驗證之前,緩存不能將其提供給客戶端使用 |
協商緩存
上面提到的強緩存都是由本地瀏覽器在確定是否使用緩存,當瀏覽器沒有命中強緩存時就會向瀏覽器發送請求,驗證協商緩存是否命中,如果緩存命中則返回304狀態碼,否則返回新的資源數據。
協商緩存(也叫對比緩存)是由服務器來確定資源是否可用,這將涉及到兩組字段成對出現的,在瀏覽器第一次發出請求時會服務器返回的響應會帶上字段(Last-Modified或者
Etag),則后續請求則會帶上對于的對應請求字段(if-modified-since或者if-none-Match),若響應頭沒有Last-Modified或者Etag,則請求頭也不會有對應的字段。
Last-modified表示本地文件最后修改時間,由服務器返回。if-modified-since是瀏覽器在請求數據時帶上的字段,值是上次服務器返回的Last-modified。ETag是一個文件的唯一標識符,當資源發生變化時這個ETag就會發生變化。彌補了上面last-modified可能出現文件內容沒有變化但是last-modified發生了變化出現重新向服務器請求資源情況。這個值也是又服務器返回的。if-none-match是瀏覽器請求數據時帶上的字段,值是上次服務器返回的ETag。
Etag/If-None-Match(標識符字符串) 與 Last-Modified/If-Modified-Since 不同的是,返回 304 時,ETag 還是會重新生成返回至瀏覽器,Etag的優先級高于Last-Modified
結合強緩存具體請求流程
- 當瀏覽器發起一個資源請求時,瀏覽器會先判斷本地是否有緩存記錄,如果沒有會向瀏覽器請求新的資源,并記錄服務器返回的
last-modified。- 如果有緩存記錄,先判斷強緩存是否存在(
cache-control優先于expires,后面會說),如果強緩存的時間沒有過期則返回本地緩存資源(狀態碼為200)- 如果強緩存失效了,客戶端會發起請求進行協商緩存策略,首先服務器判斷
Etag標識符,如果客戶端傳來標識符和當前服務器上的標識符是一致的,則返回狀態碼304 not modified(不會返回資源內容)- 如果沒有
Etag字段,服務器會對比客戶端傳過來的if-modified-match,如果這兩個值是一致的,此時響應頭不會帶有last-modified字段(因為資源沒有變化,last-modified的值也不會有變化)??蛻舳?04狀態碼之后讀取本地緩存。如果last-modified。- 如果
Etag和服務器端上的不一致,重新獲取新的資源,并進行協商緩存返回數據。
為什么需要ETag
它的出現主要是解決
last-modified幾個比較難以解決的問題
- 在沒有修改文件內容情況下文件的最后修改時間可能也會改變,這會導致客戶端認為這文件被改動了,從而重新請求
- 可能有些文件修改比較頻繁,秒級以內修改的,
If-Modified-Since能檢查到的粒度是秒級的,使用Etag就能夠保證這種需求下客戶端在 1 秒內能刷新多次。- 有些服務器不能精確獲取文件的最后修改時間
狀態碼區別
- 200 請求成功,服務器返回全新的數據
- 200
from memory cache / from disk cache本地強緩存還在有效期,直接使用本地緩存- 304 請求成功,走了協商緩存,服務器判定(
Etag和Last-modified)沒有過期,告知瀏覽器使用緩存
from memory cache :是頁面刷新的時候內存取的。
from disk cache :頁面tab關閉后從磁盤取的。
緩存優先級
expires
和cache-control如果同時存在時,cache-control會覆蓋expires,expires無效,無論是否過期,。即Cache-control > expires
強緩存和協商緩存如果同時存在時,會去先對比強緩存是否還再有效期,如果強緩存生效則對比協商緩存,即
強緩存 > 協商緩存
協商緩存
Etag和last-modified同時存在時,會先比較Etag,last-modified無效,即Etag > last-modified
刷新影響
- 當ctrl+f5強制刷新時,從服務器加載,跳過強緩存和協商緩存。
- 當f5刷新時,跳過強緩存,但是會檢查協商緩存
其他補充
- 協商緩存想要配合強緩存使用,如果不開啟強緩存使用,協商緩存沒有意義
- 大部分
web服務器默認開啟協商緩存,且是同時開啟last-modified和Etag
注意場景
- 分布式系統里
last-modified需要保持一致,以免負載到不同的機器導致比對失敗,從而返回新資源- 分布式系統盡量關閉掉
Etag,因為每一臺服務器生成的Etag是不同的

浙公網安備 33010602011771號