緩存機制一直以來是一個不可忽視的重要模塊,廣泛地被運用到 網頁端和移動端。對于服務器而言,客戶端的緩存很大程度上緩解了它的壓力,更是為用戶帶來了產品快速響應的體驗,擁有很多好處。既然是網絡請求,必然與HTTP協議聯系緊密,不論你是否有這之類的經驗,此篇將會從基礎開始總結,共同學習緩存機制。

如上圖片所示,這就是瀏覽器的緩存原理圖,以流程圖的形式描繪出了大致的緩存機制。看過幾遍后,便以為緩存機制也不過如此,移動端的緩存更是簡單,但實際并非如此,何時采取緩存?緩存何時失效?緩存失效后的做法?等等,有許多值得思考的地方,不過有些部分瀏覽器已經代替實現了,所以,先來了解瀏覽器的緩存原理:
(1)首先在有緩存的前提下,判斷緩存是否過期,因為緩存相對而言會有一個存在的有效時間,如過期的話需要進一步判斷是否向服務器發送請求。
(2)接著就是判斷 Etag ,它是關于緩存的一個字段,每次請求都會存在的一個標識符,將文本哈希編碼來標識當前文本的狀態。首先會判斷這個Etag是否存在,如果存在便會向服務器發送請求,在請求時會攜帶參數,參數If-None-Match會將Etag標記上一起發送給服務器。服務器再決策Etag是否過期,根據返回的響應碼來決定從緩存讀取還是請求響應。
(3)但是Etag 這個字段并不是必須存在的,當它不存在時,會再次判斷 Last-Modified字段是否存在,這個字段表示響應中資源最后一次修改的時間,說白了就是服務器最新一次修改文件的時間。如果存在的話,如同Etag一樣會向服務器發送請求,只是攜帶參數是會用If-Modified-Since去標識Last-Modified字段,一起發送給服務。在服務器決策時,會將Last-Modified與服務器修改文件的時間進行比較,若無變化則直接從緩存中讀取,否則請求響應,接收新的數據。
以上內容就是瀏覽器的緩存機制,了解下來并非簡單地判斷緩存過期后,就去訪問服務器,還要再次進行一系列的判斷,真正確定緩存與服務器上內容不同時,需要更新時,才是去訪問服務器請求最新數據。
這里,還需要強調一點,雖然緩存已經過期了,但是并非緩存與服務器的內容不同,比如服務端的數據并未做出任何更改,說明此時緩存的依舊是最新數據!所以還需要更詳細的判斷再來決定是否需要請求服務器更新數據,所以,避免了不必要的請求,這種緩存機制很大程度上減輕了服務器的壓力!
以下字段都是在HTTP協議中的重要字段。
此字段最初出現于 HTTP 1.0協議,指定緩存內容的失效時間(如果該文本內容支持緩存),使用的是一個絕對值。(格林威治時間GMT標準)
此字段與Expires含義相同,那為何要存在兩個含義相同的字段呢?上面有提到,Expires是一個絕對值,服務器同客戶端校驗的時候,有可能出現偏差,因為客戶端的時間可以隨意進行修改。即我們可以人為快進客戶端時間,則服務器收到該時間后判斷當前緩存已失效,可實際上緩存并未失效,所以這個字段就會出現一些問題。在HTTP 1.1協議出現了Cache-Control字段,它使用的是一個相對值,指令的參數有:
no-cache :無緩存指令,即每次請求直接從服務器獲取。”Cache-Control”: “no-cachemax-age :代表緩存的有效時間,如果緩存只是用來和服務器做驗證,可是設置更有效的”Cache-Control”:”max-age=0”。only-if-cached :先使用用緩存的數據,如果客戶端有緩存,會立即顯示客戶端的緩存,這樣你的應用程序可以在等待最新的數據下載的時候顯示一些東西, 重定向request到本地緩存資源,添加”Cache-Control”:”only-if-cached”。max-stale :即使緩存已過期,也可先展示出來。有時候過期的response比沒有response更好,設置最長過期時間來允許過期的response響應: int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale “Cache-Control”:”max-stale=” + maxStale。響應中資源最后一次修改的時間,用于判斷服務器和客戶端資源是否一致的重要字段。
也是用于判斷服務器和客戶端資源是否一致的重要字段響應中資源的校驗值,為何會存在相同意義的字段?因為如果你在服務器端修改資源后,Last-Modified會改變,可是此時客戶端與服務器端資源是否一定不同呢?也許你只是多加了一個空格,此時Last-Modified的改變意味著緩存已失效,可這樣請求服務器獲取到的數據卻是相同的。所以 HTTP協議推出了ETag, 它將服務器返回的 response整個編碼處理加密得到的一個值,在服務器上某個時段是唯一標識的,將此值與客戶端緩存中的ETag進行比較,可避免Last-Modified漏掉的問題。主旨在于比較兩者的內容是否發生變化,而不是單純的比較時間。
服務器創建報文時的時間。
(判斷緩存是否失效時標識在請求頭的標識量)客戶端存取的該資源最后一次修改的時間,同Last-Modified。
(判斷緩存是否失效時標識在請求頭的標識量)客戶端存取的該資源的檢驗值,同ETag。

以上文件是騰訊網的一個js文件,從右側可以得知:
Cache-Control:它支持緩存,緩存時間為259200秒,也就是三天。Date:表示資源發送的時間,指的是服務器的時間,與當時請求時間并非相同!Expires:資源過期的時間,用Date加上緩存有效時間 max-age而得。Last-Modified :最后一次修改的時間。Etag:改js文件被編碼加密后得到的一個標識值。以上講解的部分,已經初始了緩存機制的原理,接下來先通過一個小例子來見識 Okhttp3網絡框架的緩存機制。

以上截圖就是測試后的結果:因為騰訊網是默認有緩存的,所以我在第一次請求網絡時,電腦中并無緩存,資源從服務器上獲取,cacheResponse()返回值為null。第二次重復請求騰訊網,自然是從緩存中獲取資源。
從以上的小例子可得知Okhttp3網絡框架的緩存功能,再更詳細了解它的緩存,我在代碼中指定了將緩存放到文件夾中,在兩次請求網絡過后,文件夾多出了三個文件,如下圖所示: 

了解了HTTP協議中的字段后,發現這個內容很是熟悉,是請求騰訊網后返回的response的一些數據。比如說請求的url、請求方式、HTTP協議、返回碼,下面的就是騰訊網響應頭的數據,不妨來看看哪些與緩存相關?
Cache-Control:騰訊網支持的緩存有效時間為60秒。Date:請求資源時的服務器時間(注意!該時間與客戶端的時間是不對應的)。Expires:緩存失效時間,即Date加上緩存有效時間max-age。了解了一些基本數據后,騰訊網具體資源展示是在第二個文件,由于全部都是二進制數據,這里就不截圖展示了。
其實觀察前兩個文件名,很相似卻又有些不一樣,其實這是根據騰訊網的url加密后所得。

此文件用于 Okhttp 緩存讀取目錄時會用到的,可以查看當前客戶端請求網絡的次數和具體調用請求的地方。看第一行數據,這個也是DiskLruCache所要用到的目錄結構。
第一篇是介紹總結一下緩存機制有關的原理和Ohttp3網絡框架有關的功能,先鋪墊一下基礎。第二篇正式從解析源碼。
這里正式感謝nate老師對此的講解,我才得以總結學習,thx~
希望對你們有幫助 :)
新聞熱點
疑難解答