高級http緩存
『壹』 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緩存
在面試的時候總是遇到緩存相關問題,回答總是停留緩存就是從瀏覽器中獲取,不向伺服器發送請求,回答的不讓面試官滿意,索性抽點時間整理一下前端相關的緩存,希望下次回答的時候能夠多講點。
前端緩存分為 強緩存 和 協商緩存 ,強緩存就是在緩存未失效時,不在請求服務端,協商緩存就是去跟伺服器比較是否需要重新獲取資源 。
強緩存分為兩種, Cache-control 和 Expires , Expires 是HTTP1.0的東西,它的值是一個格林時間,比如 Expires: Wed, 21 Oct 2015 07:28:00 GMT ,由於伺服器端和瀏覽器端的時間差異問題,瀏覽器比伺服器時間快,會導致緩存失效。 Cache-control 是HTTP1.1時代的新東西,設置的是一個相對時間, Cache-Control:public, max-age=31536000 ,在31536000秒後才緩存才失效, Cache-control 有很多取值。
強緩存在緩存失效內,不會從原始伺服器獲取新的數據,假如在緩存時段內伺服器有資源更新,會導致資源獲取不及時。
協商緩存有兩組報文
『叄』 http緩存之基本概念
1. 重要性
綜上所述,所以大家很有必要花時間來研究。
2. 困難之處
個人認為http緩存是比較枯燥的理論知識,尤其對於前端來講,更多在於理解概念,以及內部緩存機制,而沒有什麼實踐可以鞏固,或者說理論和現實脫軌。
瀏覽器會在請求資源之後,根據自己的緩存策略判斷是否對資源進行緩存,當再次請求相同的資源時,瀏覽器根據緩存策略判斷是通過本地緩存獲取資源,還是重新向伺服器發起請求。
這個 緩存策略 到底是什麼呢?
實際每個瀏覽器的緩存策略是有差異的,但大致受以下幾個因素的影響。
搜索關鍵字 禁止 html 緩存 ,很容易搜到以下答案:
但是,這是 Html 4.0 中的規范,在 Html 5.0 的規范中 http-equiv 已經不存在以上屬性值了。
而且代理伺服器並不會讀取以上meta標簽,不利於代理伺服器的緩存。
-- 引用自 stackoverflow
綜上所述, html meta 是一個不那麼可靠,並且已經過時的解決方案,所以不建議再繼續使用 。
基於 HTTP 協議的緩存策略,分為 強緩存 和 協商緩存 , 由 HTTP 協議的首部 (Headers) 信息決定。具體的操作設置需要伺服器配合,比如 Nginx 。所以相對來說都是後端在做此類事情,前端接觸的機會比較少。
如果開啟了強緩存,並且在過期時間之內,則瀏覽器不再發起請求,直接使用本地的緩存資源。
Expires 和 Cache-control 用於控制強制緩存。
Expires 是 HTTP 1.0 的特性。通過指定一個明確的時間點作為緩存資源的過期時間,客戶端會根據此時間點來判斷到底使用本地緩存,還是向伺服器重新請求資源。
優點: 在緩存過期時間內,減少客戶端的 HTTP 請求,不僅節省了客戶端處理時間,提高了 web 應用的執行速度,而且減少了伺服器負載,以及客戶端網路資源的消耗。
缺點:指定的過期時間以伺服器為准,但是客戶端進行過期時間判斷時是將 本地的時間 與 指定的過期時間點 進行對比。如果客戶端修改了本地時間,將會影響對緩存的判斷。
Cache-control 是HTTP1.1 新增的特性,以便更精準地控制緩存。此首部信息 具有最高的優先順序。
max-age 指定的是緩存的時間跨度,而非緩存失效的時間點。優先順序比 Expires 高。
如果需要使用協商緩存,需要 將 Cache-control 指定為 no-cache 或者 max-age 、Expires 均過期之後。
協商緩存:瀏覽器本地是有緩存的,但是要先發起請求,由伺服器判斷緩存是否過期。
Last-Modified / If-Modified-Since
last-Modified 是 HTTP 1.0 的特性,是伺服器端在響應請求時用來說明資源的最後修改時間。
缺點:
Etag / If-None-Match
Etag 是 HTTP 1.1 的特性,是伺服器為資源分配的字元串形式唯一性標識,作為響應首部返回給瀏覽器。
採用弱比較,內容沒變化,時間變化了,會認為是資源未變化。
瀏覽器之HTTP緩存的那些事
304和瀏覽器http緩存
瀏覽器緩存機制剖析
瀏覽器緩存機制介紹
技術研究 vue項目的性能優化之路
HTTP緩存控制小結
『肆』 前端http請求細節——Cache-Control(緩存機制)
請求和響應中的 Cache-Control 指令並不完全相同,具體可以查看 這里 ,包括指令的具體意思,這里不過多贅述。(默認值:private)
瀏覽器的緩存機制是根據 HTTP 報文的緩存標識進行的,瀏覽器第一次向伺服器發起該請求後拿到請求結果,會根據響應報文中 HTTP 頭的緩存標識,決定是否緩存結果。
瀏覽器緩存策略分為兩種:強制緩存和協商緩存。
強制緩存不會向伺服器發送請求,直接從緩存中讀取資源,可以看到請求返回的狀態碼都是200,並且 Size 代表該緩存的位置。
瀏覽器讀取緩存的順序為memory –> disk。
三級緩存原理 (訪問緩存優先順序):
在瀏覽器中,瀏覽器會在js,字體,圖片等文件解析執行後直接存入內存緩存中,那麼當刷新頁面時只需直接從內存緩存中讀取(from memory cache);而css文件則會存入硬碟文件中,所以每次渲染頁面都需要從硬碟讀取緩存(from disk cache)。
為什麼CSS會放在硬碟緩存中?
因為CSS文件載入一次就可渲染出來,我們不會頻繁讀取它,所以它不適合緩存到內存中,但是js之類的腳本卻隨時可能會執行,如果腳本在磁碟當中,我們在執行腳本的時候需要從磁碟取到內存中來,這樣IO開銷就很大了,有可能導致瀏覽器失去響應。
若伺服器的資源最後被修改時間 > If-Modified-Since的欄位值
則重新返回資源,狀態碼為200;否則則返回304,代表資源無更新,可繼續使用緩存文件
If-None-Match 的欄位值 = 該資源在伺服器的Etag值
一致則返回304,代表資源無更新,繼續使用緩存文件;不一致則重新返回資源文件,狀態碼為200。
ETag 和 Last-Modified 區別
參考鏈接:
https://juejin.im/entry/5ad86c16f265da505a77dca4
https://www.cnblogs.com/suihang/p/12855345.html
https://www.jianshu.com/p/54cc04190252