『壹』 認識HTTP----緩存篇
本文內容大多參考 《圖解HTTP》一書
所以講緩存為什麼要先扯代理伺服器?別急,讓我們看一下一個請求的簡單示意圖。
我們看到客戶端(用戶)發送了一個請求並不是直接發給源伺服器的而是經過了代理伺服器,然後經由代理伺服器再發送給源伺服器,響應也同樣遵循這個順序。
那麼代理伺服器在這中間擔任了什麼角色?
緩存是指代理伺服器或客戶端本地磁碟內保存的資源副本。利用緩存可減少對源伺服器的訪問,因此也就節省了通信流量和通信時間。
緩存伺服器是代理伺服器的一種,並歸類在緩存代理類型中。換句話說,當代理轉發從伺服器返回的響應時,代理伺服器將會保存一份資源的副本。
緩存伺服器的優勢在於利用緩存可避免多次從源伺服器轉發資源。因此客戶端可就近從緩存伺服器上獲取資源,而源伺服器也不必多次處理相同的請求了。
即便緩存伺服器和客戶端內有緩存,也不能每次都給我返回緩存吧,如果是這樣,源伺服器更新了我也不知道,因為我每次都是看緩存的資源。
為了解決這個問題,針對緩存設計了時效性的概念:
即使存在緩存,也會因為客戶端的要求、緩存的有效期等因素,向源伺服器確認資源的有效性。若判斷緩存失效,緩存伺服器將會再次從源伺服器上獲取「新」資源。
緩存不僅可以存在於緩存伺服器內,還可以存在客戶端瀏覽器中。以Internet Explorer 程序為例,把客戶端緩存稱為臨時網路文件(Temporary Internet File)。
瀏覽器緩存如果有效,就不必再向伺服器請求相同的資源了,可以直接從本地磁碟內讀取。
另外,和緩存伺服器相同的一點是,當判定緩存過期後,會向源伺服器確認資源的有效性。若判斷瀏覽器緩存失效,瀏覽器會再次請求新資源。
Pragma 是HTTP/1.1 之前版本的歷史遺留欄位,僅作為與HTTP/1.0的向後兼容而定義。
規范定義的形式唯一,如下所示。
Pragma: no-cache
該首部欄位屬於通用首部欄位,但只用在客戶端發送的請求中。客戶端會要求所有的中間伺服器不返回緩存的資源。
通過指定首部欄位Cache-Control 的指令,就能操作緩存的工作機制。
可用的指令按請求和響應分類如下所示:
public指令
Cache-Control: public
當指定使用public 指令時,則明確表明其他用戶也可利用緩存。
private指令
no-store指令
Cache-Control: no-store
當使用no-store 指令時,暗示請求(和對應的響應)或響應中包含機密信息。
因此,該指令規定緩存不能在本地存儲請求或響應的任一部分。
ps:從字面意思上很容易把no-cache誤解成為不緩存,但事實上no-cache代表不緩存過期的資源,緩存會向源伺服器進行有效期確認後處理資源,也許稱為do-not-serve-from-cache-without-revalidation更合適。no-store 才是真正地不進行緩存,請讀者注意區別理解。
s-maxage指令
Cache-Control: s-maxage=604800 //(單位:秒)
s-maxage 指令的功能和max-age 指令的功能相同, 它們的不同點是s-maxage 指令只適用於供多位用戶使用的公共緩存伺服器(這里指代理伺服器)。也就是說,對於向同一用戶重復返回響應的伺服器來說,這個指令沒有任何作用。
另外,當使用s-maxage 指令後,則直接忽略對Expires 首部欄位及max-age 指令的處理。
max-age指令
cache-extension token
Cache-Control: private, community="UCI"
通過 cache-extension 標記(token),可以擴展Cache-Control 首部欄位內的指令。
如上例,Cache-Control 首部欄位本身沒有community 這個指令。藉助extension tokens 實現了該指令的添加。如果緩存伺服器不能理community 這個新指令,就會直接忽略。因此,extension tokens 僅對能理解它的緩存伺服器來說是有意義的。
If-Unmodified-Since: Thu, 03 Jul 2012 00:00:00 GMT
首部欄位If-Unmodified-Since 和首部欄位If-Modified-Since 的作用相反。它的作用的是告知伺服器,指定的請求資源只有在欄位值內指定的日期時間之後,未發生更新的情況下,才能處理請求。如果在指定日期時間後發生了更新,則以狀態碼412 Precondition Failed 作為響應返回。
ps:Last-Modified 存在一定問題,如果在伺服器上,一個資源被修改了,但其實際內容根本沒發生改變,會因為Last-Modified時間匹配不上而返回了整個實體給客戶端(即使客戶端緩存里有個一模一樣的資源)。
首部欄位If-None-Match 屬於附帶條件之一。它和首部欄位If-Match 作用相反。用於指定If-None-Match 欄位值的實體標記(ETag)值與請求資源的ETag 不一致時,它就告知伺服器處理該請求。
在GET 或HEAD 方法中使用首部欄位If-None-Match 可獲取最新的資源。因此,這與使用首部欄位If-Modified-Since 時有些類似。
不與伺服器確認,而是直接使用瀏覽器緩存的內容。其中響應內容和之前的響應內容一模一樣,例如其中的Date時間是上一次響應的時間。
F5的作用和直接在URI輸入欄中輸入然後回車是不一樣的,F5會讓瀏覽器無論如何都發一個HTTP Request給Server,即使先前的響應中有Expires頭部。
Ctrl+F5要的是徹底的從Server拿一份新的資源過來,所以不光要發送HTTP request給Server,而且這個請求裡面連If-Modified-Since/If-None-Match都沒有,這樣就逼著Server不能返回304,而是把整個資源原原本本地返回一份,這樣,Ctrl+F5引發的傳輸時間變長了,自然網頁Refresh的也慢一些。
Cache-Control 是 HTTP1.1 才有的,不適用於 HTTP1.0,而 Expires 既適用於 HTTP1.0,也適用於 HTTP1.1,所以說在大多數情況下同時發送這兩個頭會是一個更好的選擇,當客戶端兩種頭都能解析的時候,會優先使用 Cache-Control。
二者都是通過某個標識值來請求資源, 如果伺服器端的資源沒有變化,則自動返回 HTTP 304 (Not Changed)狀態碼,內容為空,這樣就節省了傳輸數據量。當資源變化後則返回新資源。從而保證不向客戶端重復發出資源,也保證當伺服器有變化時,客戶端能夠得到最新的資源。
其中Last-Modified使用文件最後修改作為文件標識值,它無法處理文件一秒內多次修改的情況,而且只要文件修改了哪怕文件實質內容沒有修改,也會重新返回資源內容;ETag作為「被請求變數的實體值」,其完全可以解決Last-Modified頭部的問題,但是其計算過程需要耗費伺服器資源。
Expires和Cache-Control都有一個問題就是服務端的修改,如果還在緩存時效里,那麼客戶端是不會去請求服務端資源的(非刷新),這就存在一個資源版本不符的問題,而強制刷新一定會發起HTTP請求並返回資源內容,無論該內容在這段時間內是否修改過;而Last-Modified和Etag每次請求資源都會發起請求,哪怕是很久都不會有修改的資源,都至少有一次請求響應的消耗。
對於所有可緩存資源,指定一個Expires或Cache-Control max-age以及一個Last-Modified或ETag至關重要。同時使用前者和後者可以很好的相互適應。
前者不需要每次都發起一次請求來校驗資源時效性,後者保證當資源未出現修改的時候不需要重新發送該資源。而在用戶的不同刷新頁面行為中,二者的結合也能很好的利用HTTP緩存控制特性,無論是在地址欄輸入URI然後輸入回車進行訪問,還是點擊刷新按鈕,瀏覽器都能充分利用緩存內容,避免進行不必要的請求與數據傳輸。
做法很簡單,就是把可能會更新的資源以版本形式發布,常用的方法是在文件名或參數帶上一串md5或時間標記符:
可以看到上面的例子中有不同的做法,有的在URI後面加上了md5參數,有的將md5值作為文件名的一部分,有的將資源放在特性版本的目錄中。
那麼在文件沒有變動的時候,瀏覽器不用發起請求直接可以使用緩存文件;而在文件有變化的時候,由於文件版本號的變更,導致文件名變化,請求的url變了,自然文件就更新了。這樣能確保客戶端能及時從伺服器收取到新修改的文件。通過這樣的處理,增長了靜態資源,特別是圖片資源的緩存時間,避免該資源很快過期,客戶端頻繁向服務端發起資源請求,伺服器再返回304響應的情況(有Last-Modified/Etag)。
『貳』 瀏覽器緩存機制簡單概括和分析
對於訪問的頁面和請求,為了縮短網頁請求資源的距離,減少延遲,並且由於緩存文件可以重復利用,還可以減少帶寬,降低網路負荷,瀏覽器和伺服器都有可能會對請求資源進行緩存,接下來的文章就簡單介紹和分析瀏覽器的緩存機制。
深入理解瀏覽器的緩存機制: https://www.jianshu.com/p/54cc04190252
這篇文章已經有詳細的講解,這里就概括一下:
以首頁的請求為例:
1、強制緩存策略(Expires和Cache-Control) :當瀏覽器發起http請求的時候,如果配置了緩存策略且緩存在有效期內,會直接使用瀏覽器緩存。 不使用強制緩存 ( Cache-Control=no-chache, 或者 max-age=0 )
(1)、圖中請求伺服器:是 max-age=0 的情況,瀏覽器直接請求伺服器資源,而不是用本地緩存
(2)、圖中磁碟緩存和內存緩存:就是瀏覽器使用了本地緩存而不再請求伺服器資源
2、協商緩存策略(Last-Modified和If-Modified-Since, ETag和If-None-Match): 當瀏覽器發起http請求的時候,如果 強制緩存策略 失效,或者者禁用了強制緩存,這時候會根據 If-Modified-Since 中的值與伺服器中這個資源的最後修改時間對比,如果沒有變化,返回304和空的響應體,直接從緩存讀取,如果If-Modified-Since的時間小於伺服器中這個資源的最後修改時間,說明文件有更新,於是返回新的資源文件和200。
不使用協商緩存 ( Cache-Control=no-store ),這個參數同時也會 禁用強制緩存。
(1)、伺服器資源返回無更新,瀏覽器使用上次請求的資源
(2)、伺服器資源有更新,返回200並返回最新的資源
3、不使用緩存策略(Cache-Control=no-store): 所有內容都不會被緩存,即不使用強制緩存,也不使用協商緩存。當response head 設置了no-store,瀏覽器不會對返回的資源做緩存,每次請求都是直接請求伺服器。這可以保證瀏覽器每次都能拿最新的資源,即使資源對比上次請求沒有任何更新,但同時也降低了頁面的響應速度,和增加了網路的IO與伺服器的壓力。
可以明顯的看到請求時間,請求伺服器資源時間 >> 請求磁碟緩存 > 請求內存緩存,所以合適的緩存策略,可以在不影響業務的情況下,極大地提升客戶體驗和後台伺服器壓力。
『叄』 http緩存過程
註:http 緩存只能緩存 get 方式請求的資源
緩存是指 代理伺服器 或 客戶端本地磁碟 內保存的資源副本。利用緩存可減少對源伺服器的訪問,因此也就節省了通信流量和通信時間。
緩存伺服器是代理伺服器的一種,並歸類在緩存代理類型中。換句話說, 當代理轉發從伺服器返回的響應時,代理伺服器將會保存一份資源的副本 。
緩存伺服器的優勢在於利用緩存可避免多次從源伺服器轉發資源。因 此客戶端可就近從緩存伺服器上獲取資源,而源伺服器也不必多次處 理相同的請求了。
瀏覽器緩存分 強制緩存 和 協商緩存 ,分別使用的欄位前者是Expires和Cach-control,後者是 Etag 和 Last-modified。
Expires (http/1.0):設的是資源的過期時間(絕對時間),瀏覽器判斷這次請求的時候是不是超過這個日期,沒超的話就直接讀取緩存中的資源,不向伺服器發請求。
Pragma :欄位值為「no-cache」的時候,會通知客戶端不要對該資源讀緩存,即每次都得向伺服器發一次請求才行。但是這種禁用緩存的形式作用不是那麼太大:1. 僅有IE才能識別這段meta標簽含義,其它主流瀏覽器僅能識別「Cache-Control: no-store」的meta標簽。2. 在IE中識別到該meta標簽含義,並不一定會在請求欄位加上Pragma,但的確會讓當前頁面每次都發新請求,但是僅限頁面,頁面上的資源則不受影響。
如果Pragma和Expires一起出現的話,Pragma的優先順序是高的。
Cach-Control (http/1.1):緩存控制 示例:
Cache-Control 有三種屬性:緩沖能力、過期時間和二次驗證。
緩沖能力:
過期時間:
二次驗證:
Expires使用的是服務端時間,可能出現客戶端和服務端時間不同步,導致本地緩存無用或無法過期。
Max-Age使用的是客戶端本地時間的計算,不會出現這個問題,推薦Max-Age。
如果同時啟用了Cache-Control和Pragma ,Expires,Cache-Control優先順序高。
Last-Modified / If- Modified-Since (http/1.0):判斷資源最後修改時間,只要這個日期改變了就不使用緩存。瀏覽器的頭部是If- Modified-Since,服務端的是Last-Modified,如果兩個匹配,代表伺服器資源未改變,服務端不會返回資源實體,只返回頭部,通知瀏覽器使用緩存。
缺點:可能有些文件會周期性地改變日期,但是內容其實沒變,但是該欄位只判斷最後修改時間,
E-tag / If-None-Match (http/1.1):Etag 是伺服器針對請求的資源文件生成的唯一標識,只要文件內容沒變化,則Etag值不變,克服了 Last-Modified / If- Modified-Since 的缺點。瀏覽器的頭部是If-None-Match,服務端的是E-tag,如果兩個匹配,代表內容未改變,通知瀏覽器使用緩存。
Etag 缺點:不適用於分布式系統 ,因為每個伺服器上的 Etag 值不同。
如果同時帶有E-tag和Last-Modified,服務端優先檢查E-tag。
『肆』 瀏覽器緩存和伺服器緩存
一、瀏覽器緩存
瀏覽器緩存即http緩存;瀏覽器緩存根據是否需要向伺服器重新發起HTTP請求將緩存過程分為兩個部分,分別是 強制緩存 和 協商緩存 。
瀏覽器第一次請求資源的時候伺服器會告訴客戶端是否應該緩存資源,根據響應報文中HTTP頭的緩存標識,決定是否緩存結果,是則將請求結果和緩存標識存入瀏覽器緩存中。如下圖:
1.強制緩存 :瀏覽器會對緩存進行查找,並根據一定的規則確定是否使用緩存。
強制緩存的緩存規則?
HTTP/1.0 Expires 這個欄位是絕對時間,比如2018年6月30日12:30,然後在這個時間點之前的請求都會使用瀏覽器緩存,除非清除了緩存。
這個欄位的缺點就是只會同步客戶端的時間,這就有可能修改客戶端時間導致緩存失效。
HTTP/1.1 cache-Control 這個是1.1的時候替換Expires的,它會有幾種取值:
public :所有內容都將被緩存(客戶端和代理伺服器都可緩存)
private :所有內容只有客戶端可以緩存, Cache-Control的默認取值
no-cache :客戶端緩存內容,但是是否使用緩存則需要經過協商緩存來驗證決定
no-store :所有內容都不會被緩存,即不使用強制緩存,也不使用協商緩存
max-age=xxx (xxx is numeric) :緩存內容將在xxx秒後失效
比如max-age=500,則在500秒內再次請求會直接只用緩存。
優先性:cache-Control > Expires
如果同時存在,cache-Control會覆蓋Expires。
這個欄位的缺點就是:
如果資源更新的速度是秒以下單位,那麼該緩存是不能被使用的,因為它的時間單位最低是秒。
如果文件是通過伺服器動態生成的,那麼該方法的更新時間永遠是生成的時間,盡管文件可能沒有變化,所以起不到緩存的作用。
上圖中瀏覽器緩存中存在該資源的緩存結果,並且沒有失效,就會直接使用緩存的內容。
上圖中瀏覽器緩存中沒有該資源的緩存結果和標識,就會直接向伺服器發起HTTP請求。
2.協商緩存: 瀏覽器的強制緩存失效後(時間過期),瀏覽器攜帶緩存標識請求伺服器,由伺服器決定是否使用緩存。
伺服器決定的規則?
控制協商緩存的欄位有 Last-Modified / If-Modified-Since 和 Etag / If-None-Match。
①Last-Modified 是伺服器返回給瀏覽器的本資源的最後修改時間。
當下次再次請求的時候,瀏覽器會在請求頭中帶 If-Modified-Since ,即上次請求下來的 Last-Modified 的值,
然後伺服器會用這個值和該資源最後修改的時間比較,如果最後修改時間大於這個值,則會重新請求該資源,返回狀態碼200。
如果這個值和最後修改時間相等,則會返回304,告訴瀏覽器繼續使用緩存。
② Etag 是伺服器返回的一個hash值。
當下次再次請求的時候,瀏覽器會在請求頭中帶 If-None-Match ,即上次請求下來的 Etag 值,
然後伺服器會用這個值和該資源在伺服器的 Etag 值比較,如果一致則會返回304,繼續使用緩存;如果不一致,則會重新請求,返回200。
二、伺服器緩存
上面是一個簡單的流程圖:
用戶1訪問A頁面,伺服器解析A頁面返回給用戶1,同時在伺服器內存上做一定映射,把A頁面緩存在硬碟上面
用戶2訪問A頁面,伺服器直接根據內存上的映射找到對應的頁面緩存,直接返回給用戶2,這樣就減少了伺服器對同一頁面的重復解析
伺服器緩存和瀏覽器緩存的區別:
伺服器緩存是把頁面緩存到伺服器上的硬碟里,而瀏覽器緩存是把頁面緩存到用戶自己的電腦里
Nginx伺服器
Nginx是一個高性能的HTTP和反向代理伺服器。具有非常多的優越性:
在連接高並發的情況下,Nginx是Apache伺服器不錯的替代品,Nginx在美國是做虛擬主機生意的老闆們經常選擇的軟體平台之一。
Nginx提供了expires、etag、if-modified-since指令來實現瀏覽器緩存控制。
nginx -s reload#重新載入配置文件
nginx -s reopen#重新打開log文件
nginx -s stop#快速關閉nginx服務
nginx -s quit #優雅的關閉nginx服務,等待工作進程處理完所有的請求
Nginx設置靜態文件的緩存過期時間
location ~.*\.(js|css|html|png|jpg)$ {
expires 3d;
}
expires 3d;//表示緩存3天
expires 3h;//表示緩存3小時
expires max;//表示緩存10年
expires -1;//表示永遠過期。
如果設置為-1在js、css等靜態文件在沒有修改的情況下返回的是http 304,如果修改返回http 200
對於靜態資源會自動添加ETag,可以通過添加etag off指令禁止生成ETag。如果是靜態文件,那麼Last-Modified值為文件的最後修改時間。
在開發調試web的時候,經常會碰到因瀏覽器緩存(cache)而經常要去清空緩存或者強制刷新來測試的煩惱,提供下apache不緩存配置和nginx不緩存配置的設置。在常用的緩存設置裡面有兩種方式,都是使用add_header來設置:分別為Cache-Control和Pragma。
location ~ .*\.(css|js|swf|php|htm|html )$ {
add_header Cache-Control no-store;
add_header Pragma no-cache;
}
nginx gzip壓縮
使用 gzip 壓縮可以降低網站帶寬消耗,同時提升訪問速度。
主要在nginx服務端將頁面進行壓縮,然後在瀏覽器端進行解壓和解析,
目前大多數流行的瀏覽器都遲滯gzip格式的壓縮,所以不用擔心。
默認情況下,Nginx的gzip壓縮是關閉的,同時,Nginx默認只對text/html進行壓縮
gzip on;
ersio #開啟gzip壓縮輸出
gzip_http_vn 1.0 ;#默認1.1
#其中的gzip_http_version的設置,它的默認值是1.1,就是說對HTTP/1.1協議的請求才會進行gzip壓縮
#如果我們使用了proxy_pass進行反向代理,那麼nginx和後端的upstream server之間是用HTTP/1.0協議通信的。
gzip_vary on ;
#和http頭有關系,加個vary頭,給代理伺服器用的,有的瀏覽器支持壓縮,有的不支持,
#所以避免浪費不支持的也壓縮,所以根據客戶端的HTTP頭來判斷,是否需要壓縮
gzip_comp_level 6;
#設置gzip壓縮等級,等級越底壓縮速度越快文件壓縮比越小,反之速度越慢文件壓縮比越大 1-9
gzip_proxied any;
#Ngnix作為反向代理的時候啟用
#expample:gzip_proxied no-cache;
# off – 關閉所有的代理結果數據壓縮
# expired – 啟用壓縮,如果header中包含」Expires」頭信息
# no-cache – 啟用壓縮,如果header中包含」Cache-Control:no-cache」頭信息
# no-store – 啟用壓縮,如果header中包含」Cache-Control:no-store」頭信息
# private – 啟用壓縮,如果header中包含」Cache-Control:private」頭信息
# no_last_modified – 啟用壓縮,如果header中包含」Last_Modified」頭信息
# no_etag – 啟用壓縮,如果header中包含「ETag」頭信息
# auth – 啟用壓縮,如果header中包含「Authorization」頭信息
# any – 無條件壓縮所有結果數據
gzip_types text/html ;#壓縮的文件類型
#設置需要壓縮的MIME類型,非設置值不進行壓縮
#param:text/html|application/x-javascript|text/css|application/xml
gzip_buffers 16 8k; #設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間
#設置gzip申請內存的大小,其作用是按塊大小的倍數申請內存空間
# param1:int 增加的倍數
# param2:int(k) 後面單位是k
# example: gzip_buffers 4 8k;
# Disable gzip for certain browsers.
gzip_disable 「MSIE [1-6].(?!.*SV1)」; #ie6不支持gzip,需要禁用掉ie6
『伍』 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的實現原理。