http請求緩存
『壹』 瀏覽器緩存機制
有dns的地方,就有緩存。瀏覽器、操作系統、Local DNS、根域名伺服器,它們都會對DNS結果做一定程度的緩存。
DNS查詢過程如下:
首先搜索瀏覽器自身的DNS緩存,如果存在,則域名解析到此完成。
如果瀏覽器自身的緩存裡面沒有找到對應的條目,那麼會嘗試讀取操作系統的hosts文件看是否存在對應的映射關系,如果存在,則域名解析到此完成。
如果本地hosts文件不存在映射關系,則查找本地DNS伺服器(ISP伺服器,或者自己手動設置的DNS伺服器),如果存在,域名到此解析完成。
如果本地DNS伺服器還沒找到的話,它就會向根伺服器發出請求,進行遞歸查詢。
瀏覽器本地緩存失效後,瀏覽器會向CDN邊緣節點發起請求。類似瀏覽器緩存,CDN邊緣節點也存在著一套緩存機制。CDN邊緣節點緩存策略因服務商不同而不同,但一般都會遵循http標准協議,通過http響應頭中的
Cache-control: max-age 的欄位來設置CDN邊緣節點數據緩存時間。
當瀏覽器向CDN節點請求數據時,CDN節點會判斷緩存數據是否過期,若緩存數據並沒有過期,則直接將緩存數據返回給客戶端;否則,CDN節點就會向伺服器發出回源請求,從伺服器拉取最新數據,更新本地緩存,並將最新數據返回給客戶端。 CDN服務商一般會提供基於文件後綴、目錄多個維度來指定CDN緩存時間,為用戶提供更精細化的緩存管理。
CDN 優勢
CDN節點解決了跨運營商和跨地域訪問的問題,訪問延時大大降低。
大部分請求在CDN邊緣節點完成,CDN起到了分流作用,減輕了源伺服器的負載。
http請求報文(request)
請求行
請求方法 空格 URL 空格 協議版本 回車符 換行符
請求頭(通用信息頭、請求頭、實體頭)
頭部欄位名 冒號 值 回車鍵 換行符
...
頭部欄位名 冒號 值 回車鍵 換行符
空行
回車符 換行符
實體主體(只有post請求有)
主體
http響應報文(response)
狀態行
協議版本 空格 狀態碼 空格 狀態碼描述 回車符 換行符
響應頭部
頭部欄位名 冒號 值 回車符 換行符
...
頭部欄位名 冒號 值 回車符 換行符
空行
回車符 換行符
響應正文
正文
瀏覽器初次向伺服器發起請求後拿到請求結果,會根據響應報文中HTTP頭的緩存標識,決定是否緩存返回的結果,是則將請求結果和緩存標識存入瀏覽器緩存中
瀏覽器每次發起請求,都會現在瀏覽器緩存中查找該請求的結果以及緩存標識
瀏覽器 瀏覽器緩存 伺服器
——————第一次發起http請求——————>
<——沒有該請求的緩存結果和緩存標識————
——————————————發起http請求——————————————>
<——————————返回該請求結果和緩存規則————————————
——將請求結果和緩存標識存入瀏覽器緩存——>
強制緩存就是向瀏覽器緩存查找結果,並根據該結果的緩存規則來決定是否使用該緩存結果的過程
強制緩存的情況分為三種:
1、不存在該緩存結果和緩存標識,強制緩存失效,直接向伺服器發起請求
2、存在該緩存結果和緩存標識,但結果已經失效,強制緩存失效,使用協商緩存
3、存在該緩存結果和緩存標識,且該結果沒有失效,強制緩存生效,直接返回該結果
控制強制緩存的欄位:Expires,Cache-Control
Expires 是 HTTP/1.0 控制緩存的欄位,值為伺服器返回該請求的結果緩存時間
即再次發送請求是,客戶端時間 小於 Expires的值,直接使用緩存結果
Cache-Control 是HTTP/1.1的規則,主要用於控制網頁緩存,主要取值為:
public:所有的內容都緩存(客戶端和代理伺服器都可以緩存)
private:所有內容只有客戶端可以緩存(默認值)
no-cache:客戶端緩存內容,但是是否使用緩存則需要經過協商緩存來驗證決定
no-store:即不使用強制緩存,也不使用協商緩存
max-age=xxx:緩存內容將在xxx秒後失效
Expires 是一個絕對值
Cache-Control 中 max-age 是相對值,解決了 Expires時期 服務端與客戶端 可能出現時間差的問題
註:Expires和Cache-Control同時存在時,只有Cache-Control生效
協商緩存就是強制緩存失效後,瀏覽器攜帶緩存標識向伺服器發起請求,由伺服器根據緩存標識決定是否使用緩存的過程
協商緩存的兩種情況:
1、協商緩存生效,返回304,繼續使用緩存
過程:
瀏覽器 瀏覽器緩存 伺服器
————————發起http請求————————>
<——該請求的緩存結果失效,只返回緩存標識——
————————攜帶該資源的緩存標識,發起http請求————————>
<—————————————304,該資源無更新————————————
——————獲取該請求的緩存結果——————>
<——————返回該請求的緩存結果——————
2、協商緩存失敗,返回200和請求結果
過程:
瀏覽器 瀏覽器緩存 伺服器
————————發起http請求————————>
<——該請求的緩存結果失效,只返回緩存標識——
————————攜帶該資源的緩存標識,發起http請求————————>
<————————200,資源已更新,重新返回請求和結果———————
——將該請求結果和緩存標識存入瀏覽器緩存中—>
協商緩存的標識也是在響應報文的HTTP頭中和請求結果一起返回給瀏覽器的
控制協商緩存的欄位:
(1) Last-Modified/If-Modified-Since:Last-Modified是伺服器響應請求是,返回該資源文件在伺服器最後被修改的時間;If-Modified-Since再次發起請求時,攜帶上次返回的Last-Modified的值,伺服器將該欄位值與該資源最後修改時間對比,決定是否用緩存
(2)Etag/If-None-Match:Etag伺服器響應請求時,返回當前資源文件的一個唯一標識,由伺服器生成之;If-None-Match是再次發起請求時,攜帶上次返回的唯一標識Etag的值,伺服器收到後,將該欄位值與該資源在伺服器上的Etag對比,一致 則返回304,否則返回200
註:Etag/If-None-Match優先順序高於Last-Modified/If-Modified-Since,同時存在時只有Etag/If-None-Match生效
瀏覽器緩存分為:內存緩存 和 硬碟緩存
內存緩存特性:
(1)快速讀取:內存緩存會將編譯解析後的文件,存入該進程的內存中,便於下次運行時快速讀取
(2)時效性:一旦關閉進程,進程內存清空
硬碟緩存特性:
永久性:直接寫入硬碟文件中
復雜、緩慢:讀取緩存對該緩存存放的硬碟文件進行I/O操作,重新解析
from memory cache:使用內存中的緩存
from disk cache:使用硬碟中的緩存
瀏覽器讀取順序:memory ——> disk
瀏覽器將js和圖片等文件解析執行後直接存入內存緩存中,F5刷新頁面時,from memory cache(使用內存中的緩存)
css文件存入硬碟中,F5刷新頁面時,from disk cache(使用硬碟中的緩存)
參考文章
https://segmentfault.com/a/1190000017962411
https://www.cnblogs.com/chengxs/p/10396066.html
『貳』 Okhttp解析(五)緩存的處理
大家好,之前我們講解了Okhttp網路數據請求相關的內容,這一節我們講講數據緩存的處理。本節按以下內容講解Okhttp緩存相關的內容。
緩存的使用場景很多,通過它可以將數據通過一定的規則存儲起來,再次請求數據的時候就可以快速從緩存中讀取了,緩存有以下優勢。
HTTP本身提供了一套緩存相關的機制。這套機制定義了相關的欄位和規則,用來客戶端和服務端進行緩存相關的協商,如響應的數據是否需要緩存,緩存有效期,緩存是否有效,伺服器端給出指示,而客戶端則根據服務端的指示做具體的緩存更新和讀取緩存工作。http緩存可以分為兩類:
強制緩存,在緩存數據未失效的情況下,可以直接使用緩存數據,有兩個欄位Expires和Cache-Control用於標明失效規則。
表示過期時間,由服務端返回。那麼下次請求數據時,判斷這個Expires過期時間是否已經過了,如果還沒有到過期時間,則使用緩存,如果過了過期時間,則重新請求伺服器的數據。Expires格式如下:
不過因為伺服器和客戶端的時間並不是同步的,用一個絕對時間作為過期的標記並不是很明智,所以HTTP1.1之後更多的是Cache-Control,它的控制更加靈活。
表示緩存的控制,有服務端返回。它有以下幾個取值:
默認情況下是private,也就是不能共享的。Cache-Control格式如下:
對比緩存,表示需要和服務端進行相關信息的對比,由伺服器決定是使用緩存還是最新內容,如果伺服器判定使用緩存,返回響應嗎304,判定使用最新內容,則返回響應碼200和最新數據。對比緩存的判定欄位有兩組:
ETag表示資源的一種標識信息,用於標識某個資源,由服務端返回,優先順序更高。格式如下:
然後客戶端再次請求時,加入欄位If-None-Match,格式如下:
服務端收到請求的該欄位時(之前的Etag值),和資源的唯一標識進行對比,如果相同,說明沒有改動,則返回狀態碼304,如果不同,說明資源被改過了,則返回狀態碼200和整個內容數據。
Last-Modified表示資源的最近修改時間,由服務端返回,優先順序更低。格式如下:
Last-Modified
由伺服器返回,表示響應的數據最近修改的時間。
If-Modified-Since
由客戶端請求,表示詢問伺服器這個時間是不是上次修改的時間。如果服務端該資源的修改時間小於等於If-Modified-Since指定的時間,說明資源沒有改動,返回響應狀態碼304,可以使用緩存。如果服務端該資源的修改時間大於If-Modified-Since指定的時間,說明資源又有改動了,則返回響應狀態碼200和最新數據給客戶端,客戶端使用響應返回的最新數據。
Last-Modified欄位的值(服務端返回的資源上次修改時間),常常被用於客戶端下次請求時的If-Modified-Since欄位中。
HTTP的緩存規則是優先考慮強制緩存,然後考慮對比緩存。
Okhttp緩存相關的類有如下:
要開啟使用Okhttp的緩存其實很簡單,只需要給OkHttpClient對象設置一個Cache對象即可,創建一個Cache時指定緩存保存的目錄和緩存最大的大小即可。
那麼下面我們來看看Okhttp緩存執行的大概流程
Okhttp的緩存流程分為讀取緩存和存儲緩存兩個過程,我們分別分析。
讀取使用緩存的流程從HttpEngine的sendRequest發送請求開始。
接下來我們分析
從Cache的get方法開始。它按以下步驟進行。
如果存在緩存的話,在指定的緩存目錄中,會有兩個文件「****.0」和「****.1」,分別存儲某個請求緩存的響應頭和響應體信息。(「****」是url的md5加密值)對應的ENTRY_METADATA響應頭和ENTRY_BODY響應體。緩存的讀取其實是由DiskLruCache來讀取的,DiskLruCache是支持Lru(最近最少訪問)規則的用於磁碟存儲的類,對應LruCache內存存儲。它在存儲的內容超過指定值之後,就會根據最近最少訪問的規則,把最近最少訪問的數據移除,以達到總大小不超過限制的目的。
接下來我們分析CacheStrategy緩存策略是怎麼判定的。
直接看CacheStrategy的get方法。緩存策略是由請求和緩存響應共同決定的。
接來下我們看看CacheControl類里有些什麼。
可以發現,它就是用於描述響應的緩存控制信息。
然後我們再看看Okhttp存儲緩存是怎麼進行的。
存儲緩存的流程從HttpEngine的readResponse發送請求開始的。
可以看到這里先通過maybeCache寫入了響應頭信息,再通過cacheWritingResponse寫入了響應體信息。我們再進去看Cache的put方法實現。
我們繼續看Cache的writeTo方法,可以看到是寫入一些響應頭信息。
到這里Okhttp緩存的讀取和存儲流程我們就清楚了。可以說,緩存的使用策略基本都是按照HTTP的緩存定義來實現的,所以對HTTP緩存相關欄位的理解是很重要的。然後關於DiskLruCache是如何管理緩存文件的,這個其實也很好理解,首先的原則就是按照LRU這種最近最少使用刪除的原則,當總的大小超過限定大小後,刪除最近最少使用的緩存文件,它的LRU演算法是使用LinkedHashMap進行維護的,這樣來保證,保留的緩存文件都是更常使用的。具體實現大家可以分析DiskLruCache和LinkedHashMap的實現原理。
『叄』 瀏覽器緩存(http緩存)
瀏覽器緩存有兩種:強制緩存和協商緩存
向瀏覽器緩存中查找請求結果,根據【緩存規則】決定是否使用該結果。
強制緩存失效後,攜帶緩存標識請求伺服器,伺服器根據緩存標識判斷是否使用緩存
當瀏覽器向伺服器發送請求的時候,伺服器會將緩存規則放入HTTP響應的報文的HTTP頭中和請求結果一起返回給瀏覽器(ps:下文說的時間點均為類似:Sat Aug 14 2021 11:01:52,秒級)
兩個欄位:Expires和Cache-Control,優先順序:Cache-Control > Expires,客戶端比較時間
Expires :HTTP/1.0,返回值為【到期時間點】,再次請求,客戶端的時間< Expires,直接用緩存(ps:客戶端與伺服器端時間可能存在誤差,出問題)
Cache-Control :HTTP/1.1,有以下欄位
Last-Modified / If-Modified-Since 和 Etag / If-None-Match,優先順序Etag > Last-Modified,伺服器比較時間
Last-Modified(服務端返回客戶端) / If-Modified-Since(客戶端傳入服務端) :兩個冊慎值相同,表示:資源文件在伺服器最後裂姿談被修改的時間【時間點】。
Etag(服務端返回客戶端) / If-None-Match(客戶端傳入服務端) ,兩個值相同,為當前資源文件的一個唯一標識(由伺服器生成)
Etag什麼時候用
雅虎禁用了Etag:因為ETag的值和伺服器有關,那麼對於同樣的文件,可能下次請求的時候是發給不同的伺服器,結果也會重新發送數據,所以就會影響網頁載入速度,增加伺服器的壓力(但Last-Modified也與伺服器有關)
主要解決的問題:
瀏覽器的每個tab都是一個進程
兩個緩存的肆碰地方 from memory cache(內存緩存) 和 from disk cache(硬碟緩存) ,讀取順序為memory > disk