版權聲明:web
本帳號發佈文章均來自公衆號,承香墨影(cxmyDev),版權歸承香墨影全部。瀏覽器
未經容許,不得轉載。緩存
在 Android 開發中,若是用過 WebView 來加載一個網頁,老是逃不過 WebView 的緩存策略的設定。WebView 自己也提供了多種緩存的策略來供開發者使用,而有一些涉及到 Http 協議,因此將兩個概念集中整理一塊兒講解,但願對你們有幫助。服務器
WebView 自己是提供了設置緩存策略的 API 的,可使用 WebSetting 對象進行設置。網絡
而 WebSetting 中,能夠設置多種緩存策略,以下:post
LOAD_CACHE_ONLY 和 LOAD_NO_CACHE 都是比較極端的狀況,通常咱們也不會使用。LOAD_NORMAL 已經被廢棄了,也沒什麼好說的,而 LOAD_CACHE_ELSE_NETWORK 自己已經決定了策略,只要本地有,就不會從新獲取,也不會有什麼能夠變化的。測試
LOAD_DEFAULT 纔是咱們項目上比較經常使用測策略,本文主要對 LOAD_DEFAULT 模式進行講解,自己它也是 WebView 的默認模式。可是實際開發中,最好仍是顯式設定一下,不少 ROM 均可能會修改這部分代碼的,我在樂視手機上作過測試,它的默認策略就是 LOAD_CACHE_ELSE_NETWORK 。3d
先來看看 LOAD_DEFAULT 的 API。code
能夠看到,它是默認策略,若是不設定強制策略,在資源沒有過時的時候,從緩存獲取,若是資源過時了,則從網絡獲取。cdn
這樣的一個策略,就和 Http 緩存相關了,由協議來肯定資源加載的策略。
既然知道 WebView 也是遵循 Http 的緩存策略的,那麼咱們就先來看看 Http 緩存的策略是怎麼樣的。
用 Charles 抓一個包,看看一個常規的靜態文件。
能夠看到,一個請求的響應頭中,包含了不少信息,而其中有一部分是和緩存相關的,下面咱們來一一講解。
Cache-Control 是 Http 1.1 中新增長的一個用來定義緩存時間的頭。若是使用了 Cache-Control 的話,會覆蓋掉 Http 1.0 中的一些,例如:Pragma、Expires等,以 Cache-Control 爲準。
Cache-Control 也是一個通用的 Http 報文頭字段,它能夠分別在請求報文和響應報文中使用,而它做爲不一樣的使用方式,存在不一樣的含義。
Cache-Control 的規範寫法:
Cache-Control:cache-directive
cache-directive 的可選值有不少,no-cache、no-store、only-if-cached 等,有興趣的能夠自行查查 Http 協議中的定義。可是通常而言,如上圖所示,會使用 max-age 來設定一個最大的有效時間的方式來使用,max-age 設定的時間,單位爲秒(s)。
Cache-Control 的 max-age 出如今請求報文頭和響應報文頭中,含義是不同的。
WebView 中,若是被設定爲 LOAD_DEFAULT 的話,是遵循此規則的,也就是說,當請求資源回來以後,會根據 max-age 設定當前資源的過時時間,在這個時間範圍內,則不會從新請求,會直接從緩存中讀取資源,而上面的例子中,max-age 被設定爲 40000,差很少 11 個多小時。
Cache-Control 這個報文頭,決定了客戶端是否須要向服務器發送請求。可是,若是已通過期(超過 max-age 設定的時間),當這個請求發送到服務器以後,是否須要服務器返回一個完整的數據呢?
雖然咱們設定了 max-age ,可是它只能表示一個合理的變化頻度,也就是說,可能超過這個 max-age 設定的時間,可是請求的文件也並無變化。那麼服務器只須要告知客戶端,文件沒變化,你仍是讀緩存的資源就行了。
這個策略,就是使用 ETag 和 Last-Modified 來校驗的。當客戶端經過 max-age 判斷髮現請求的資源文件已經再也不新鮮了,須要從服務器上從新獲取,在向服務器發送請求的時候,就會經過這些值告知服務器本地緩存資源的一個標識,服務器就經過這個標識來判斷客戶端緩存的資源是否依然新鮮。
能夠看到,當 max-age 失效以後,發送的請求,會攜帶 if-None-Match 和 if-Modified-Since 這兩個報文頭,服務器就是根據這兩個報文頭來斷定客戶端的資源是否過時,若是過時,則返回新的資源,若是未過時,則返回一個狀態碼304的一個響應,告知客戶端能夠繼續讀取緩存使用。
細心的應該能夠看到,請求頭裏的 if-None-Match 就是以前響應頭裏的 ETag ,而 if-Modified-Since 就是以前響應頭裏的 Last-Modified。
下面看看他們的含義:
固然,對於請求頭,還有其餘的規則,例如:if-Match、if-Unmodified-Since 等,這個就看服務器的和客戶端的實現了。
這裏的 ETag 和 Last-Modified 其實能夠分開使用,可是若是被同時使用,則要求服務器對這兩個值都進行校驗,都校驗經過了纔會返回 304。
那麼這麼作,有什麼好處,實際是全部的緩存策略,都是爲了減少各類地方的壓力。對於客戶端而言,減小了網絡請求的壓力,對於服務器而言,也減少了請求和流量的壓力。
能夠看到,一個完整的資源請求,須要 24kb,而當資源沒有過時的時候,只須要 1kb 左右便可,而且響應的時間也更快了。
到這裏,對於 WebView 的各個緩存策略的理解應該就明確了。若是使用 LOAD_DEFAULT 則依賴 Http 的緩存策略,而Http 緩存又是依賴 Cache-Control、ETag、Last-Modified 等值來肯定的。
那麼,若是咱們將 CacheMode 設定爲 LOAD_DEFAULT ,而且給出了一個 max-age = 40000 資源響應頭,在不清理緩存的狀況下,咱們的 WebView 就不會對該繼續發送請求?這樣咱們不當心設定了一個極大的 max-age 值,是否客戶端的資源好久纔會被更新?
其實並非絕對的,在 WebView 中,加載網頁,咱們通常使用 loadUrl() 方法,當使用 loadUrl() 方法的時候,它會徹底遵循上面給出的緩存策略,在沒有過時的時候去從緩存中讀取資源。
可是瀏覽器在 Http 緩存策略以外,還提供了強制刷新的策略,這樣也保證了在某些狀況下,能夠去服務器是從新獲取資源。而這個策略反應在 WebView 中,就是使用 reload() 方法。當使用 reload() 方法的時候,WebView 會從新請求資源,並在報文頭中,修改 max-age 爲 0 。這樣既能夠保證當前刷新了會有一個真實的網絡請求,又能保證在緩存資源不過時的狀況下,不給服務器形成壓力。
Http 的緩存策略,在 Android 開發中,並非只用在 WebView 上,一些網絡庫,例如 OkHttp,也是依賴 Http 緩存策略來進行緩存數據的。
本文參加掘金技術徵文:juejin.im/post/58d8e9…