從WebView緩存聊到Http 的緩存機(jī)制

版權(quán)聲明:

本賬號(hào)發(fā)布文章均來(lái)自公眾號(hào),承香墨影(cxmyDev),版權(quán)歸承香墨影所有怀吻。

未經(jīng)允許,不得轉(zhuǎn)載惠遏。

一、前言

在 Android 開(kāi)發(fā)中骏啰,如果用過(guò) WebView 來(lái)加載一個(gè)網(wǎng)頁(yè)节吮,總是逃不過(guò) WebView 的緩存策略的設(shè)定。WebView 本身也提供了多種緩存的策略來(lái)供開(kāi)發(fā)者使用判耕,而有一些涉及到 Http 協(xié)議透绩,所以將兩個(gè)概念集中整理一起講解,希望對(duì)大家有幫助壁熄。

二帚豪、WebView 緩存策略

WebView 本身是提供了設(shè)置緩存策略的 API 的,可以使用 WebSetting 對(duì)象進(jìn)行設(shè)置草丧。

而 WebSetting 中狸臣,可以設(shè)置多種緩存策略,如下:

  • LOAD_CACHE_ONLY:不使用網(wǎng)絡(luò)昌执,只讀本地緩存烛亦。
  • LOAD_NORMAL:在 API Level 17 中已經(jīng)被廢棄,而在API Level 11 開(kāi)始懂拾,策略如 LOAD_DEFALT煤禽。
  • LOAD_NO_CACHE:不使用緩存,只從網(wǎng)絡(luò)獲取數(shù)據(jù)委粉。
  • LOAD_CACHE_ELSE_NETWORK:只要本地有緩存呜师,就從緩存中讀取數(shù)據(jù)。
  • LOAD_DEFAULT:根據(jù) Http 協(xié)議贾节,決定是否從網(wǎng)絡(luò)獲取數(shù)據(jù)汁汗。

LOAD_CACHE_ONLY 和 LOAD_NO_CACHE 都是比較極端的情況,一般我們也不會(huì)使用栗涂。LOAD_NORMAL 已經(jīng)被廢棄了知牌,也沒(méi)什么好說(shuō)的,而 LOAD_CACHE_ELSE_NETWORK 本身已經(jīng)決定了策略斤程,只要本地有角寸,就不會(huì)重新獲取,也不會(huì)有什么可以變化的忿墅。

LOAD_DEFAULT 才是我們項(xiàng)目上比較常用測(cè)策略扁藕,本文主要對(duì) LOAD_DEFAULT 模式進(jìn)行講解,本身它也是 WebView 的默認(rèn)模式疚脐。但是實(shí)際開(kāi)發(fā)中亿柑,最好還是顯式設(shè)定一下,很多 ROM 都可能會(huì)修改這部分代碼的棍弄,我在樂(lè)視手機(jī)上做過(guò)測(cè)試望薄,它的默認(rèn)策略就是 LOAD_CACHE_ELSE_NETWORK 。

先來(lái)看看 LOAD_DEFAULT 的 API呼畸。

可以看到痕支,它是默認(rèn)策略,如果不設(shè)定強(qiáng)制策略蛮原,在資源沒(méi)有過(guò)期的時(shí)候卧须,從緩存獲取,如果資源過(guò)期了儒陨,則從網(wǎng)絡(luò)獲取花嘶。

這樣的一個(gè)策略,就和 Http 緩存相關(guān)了框全,由協(xié)議來(lái)確定資源加載的策略察绷。

三、Http緩存策略

既然知道 WebView 也是遵循 Http 的緩存策略的津辩,那么我們就先來(lái)看看 Http 緩存的策略是怎么樣的拆撼。

用 Charles 抓一個(gè)包,看看一個(gè)常規(guī)的靜態(tài)文件喘沿。

可以看到闸度,一個(gè)請(qǐng)求的響應(yīng)頭中,包含了很多信息蚜印,而其中有一部分是和緩存相關(guān)的莺禁,下面我們來(lái)一一講解。

1窄赋、Cache-Control

Cache-Control 是 Http 1.1 中新增加的一個(gè)用來(lái)定義緩存時(shí)間的頭哟冬。如果使用了 Cache-Control 的話楼熄,會(huì)覆蓋掉 Http 1.0 中的一些,例如:Pragma浩峡、Expires等可岂,以 Cache-Control 為準(zhǔn)。

Cache-Control 也是一個(gè)通用的 Http 報(bào)文頭字段翰灾,它可以分別在請(qǐng)求報(bào)文和響應(yīng)報(bào)文中使用缕粹,而它作為不同的使用方式,存在不同的含義纸淮。

Cache-Control 的規(guī)范寫法:

Cache-Control:cache-directive

cache-directive 的可選值有很多平斩,no-cache、no-store咽块、only-if-cached 等绘面,有興趣的可以自行查查 Http 協(xié)議中的定義。但是一般而言糜芳,如上圖所示飒货,會(huì)使用 max-age 來(lái)設(shè)定一個(gè)最大的有效時(shí)間的方式來(lái)使用,max-age 設(shè)定的時(shí)間峭竣,單位為秒(s)塘辅。

Cache-Control 的 max-age 出現(xiàn)在請(qǐng)求報(bào)文頭和響應(yīng)報(bào)文頭中,含義是不一樣的皆撩。

  • 請(qǐng)求頭:告知服務(wù)器客戶端希望接收一個(gè)存在時(shí)間(Age)不大于 max-age 的資源扣墩。
  • 響應(yīng)頭:告知客戶端,該資源在 max-age 設(shè)定的時(shí)間內(nèi)是新鮮的扛吞,無(wú)需再向服務(wù)器發(fā)送請(qǐng)求了呻惕。

WebView 中,如果被設(shè)定為 LOAD_DEFAULT 的話滥比,是遵循此規(guī)則的亚脆,也就是說(shuō),當(dāng)請(qǐng)求資源回來(lái)之后盲泛,會(huì)根據(jù) max-age 設(shè)定當(dāng)前資源的過(guò)期時(shí)間濒持,在這個(gè)時(shí)間范圍內(nèi),則不會(huì)重新請(qǐng)求寺滚,會(huì)直接從緩存中讀取資源柑营,而上面的例子中,max-age 被設(shè)定為 40000村视,差不多 11 個(gè)多小時(shí)官套。

2、數(shù)據(jù)新鮮度校驗(yàn)

Cache-Control 這個(gè)報(bào)文頭,決定了客戶端是否需要向服務(wù)器發(fā)送請(qǐng)求奶赔。但是惋嚎,如果已經(jīng)過(guò)期(超過(guò) max-age 設(shè)定的時(shí)間),當(dāng)這個(gè)請(qǐng)求發(fā)送到服務(wù)器之后纺阔,是否需要服務(wù)器返回一個(gè)完整的數(shù)據(jù)呢瘸彤?

雖然我們?cè)O(shè)定了 max-age 修然,但是它只能表示一個(gè)合理的變化頻度笛钝,也就是說(shuō),可能超過(guò)這個(gè) max-age 設(shè)定的時(shí)間愕宋,但是請(qǐng)求的文件也并沒(méi)有變化玻靡。那么服務(wù)器只需要告知客戶端,文件沒(méi)變化中贝,你還是讀緩存的資源就好了囤捻。

這個(gè)策略,就是使用 ETag 和 Last-Modified 來(lái)校驗(yàn)的邻寿。當(dāng)客戶端通過(guò) max-age 判斷發(fā)現(xiàn)請(qǐng)求的資源文件已經(jīng)不再新鮮了蝎土,需要從服務(wù)器上重新獲取,在向服務(wù)器發(fā)送請(qǐng)求的時(shí)候绣否,就會(huì)通過(guò)這些值告知服務(wù)器本地緩存資源的一個(gè)標(biāo)識(shí)誊涯,服務(wù)器就通過(guò)這個(gè)標(biāo)識(shí)來(lái)判斷客戶端緩存的資源是否依然新鮮。

可以看到蒜撮,當(dāng) max-age 失效之后暴构,發(fā)送的請(qǐng)求,會(huì)攜帶 if-None-Match 和 if-Modified-Since 這兩個(gè)報(bào)文頭段磨,服務(wù)器就是根據(jù)這兩個(gè)報(bào)文頭來(lái)判定客戶端的資源是否過(guò)期取逾,如果過(guò)期,則返回新的資源苹支,如果未過(guò)期砾隅,則返回一個(gè)狀態(tài)碼304的一個(gè)響應(yīng),告知客戶端可以繼續(xù)讀取緩存使用债蜜。

細(xì)心的應(yīng)該可以看到晴埂,請(qǐng)求頭里的 if-None-Match 就是之前響應(yīng)頭里的 ETag ,而 if-Modified-Since 就是之前響應(yīng)頭里的 Last-Modified策幼。

下面看看他們的含義:

  • ETag:資源的唯一匹配標(biāo)識(shí)信息邑时。
  • Last-Modified:資源的最后一次修改時(shí)間。
  • if-None-Match:比較 ETag 是否不一致特姐。
  • If-Modified-Since:比較資源最后更新的時(shí)間是否一致晶丘。

當(dāng)然,對(duì)于請(qǐng)求頭,還有其他的規(guī)則浅浮,例如:if-Match沫浆、if-Unmodified-Since 等,這個(gè)就看服務(wù)器的和客戶端的實(shí)現(xiàn)了滚秩。

這里的 ETag 和 Last-Modified 其實(shí)可以分開(kāi)使用专执,但是如果被同時(shí)使用,則要求服務(wù)器對(duì)這兩個(gè)值都進(jìn)行校驗(yàn)郁油,都校驗(yàn)通過(guò)了才會(huì)返回 304本股。

那么這么做,有什么好處桐腌,實(shí)際是所有的緩存策略拄显,都是為了減小各種地方的壓力。對(duì)于客戶端而言案站,減少了網(wǎng)絡(luò)請(qǐng)求的壓力躬审,對(duì)于服務(wù)器而言,也減小了請(qǐng)求和流量的壓力蟆盐。

可以看到承边,一個(gè)完整的資源請(qǐng)求,需要 24kb石挂,而當(dāng)資源沒(méi)有過(guò)期的時(shí)候博助,只需要 1kb 左右即可,并且響應(yīng)的時(shí)間也更快了誊稚。

四翔始、例外情況

到這里,對(duì)于 WebView 的各個(gè)緩存策略的理解應(yīng)該就明確了里伯。如果使用 LOAD_DEFAULT 則依賴 Http 的緩存策略城瞎,而Http 緩存又是依賴 Cache-Control、ETag疾瓮、Last-Modified 等值來(lái)確定的脖镀。

那么,如果我們將 CacheMode 設(shè)定為 LOAD_DEFAULT 狼电,并且給出了一個(gè) max-age = 40000 資源響應(yīng)頭蜒灰,在不清理緩存的情況下,我們的 WebView 就不會(huì)對(duì)該繼續(xù)發(fā)送請(qǐng)求肩碟?這樣我們不小心設(shè)定了一個(gè)極大的 max-age 值强窖,是否客戶端的資源很久才會(huì)被更新?

其實(shí)并不是絕對(duì)的削祈,在 WebView 中翅溺,加載網(wǎng)頁(yè)脑漫,我們一般使用 loadUrl() 方法,當(dāng)使用 loadUrl() 方法的時(shí)候咙崎,它會(huì)完全遵循上面給出的緩存策略优幸,在沒(méi)有過(guò)期的時(shí)候去從緩存中讀取資源。

但是瀏覽器在 Http 緩存策略之外褪猛,還提供了強(qiáng)制刷新的策略网杆,這樣也保證了在某些情況下,可以去服務(wù)器是重新獲取資源伊滋。而這個(gè)策略反應(yīng)在 WebView 中碳却,就是使用 reload() 方法。當(dāng)使用 reload() 方法的時(shí)候新啼,WebView 會(huì)重新請(qǐng)求資源追城,并在報(bào)文頭中,修改 max-age 為 0 燥撞。這樣既可以保證當(dāng)前刷新了會(huì)有一個(gè)真實(shí)的網(wǎng)絡(luò)請(qǐng)求,又能保證在緩存資源不過(guò)期的情況下迷帜,不給服務(wù)器造成壓力物舒。

五、小結(jié)

Http 的緩存策略戏锹,在 Android 開(kāi)發(fā)中冠胯,并不是只用在 WebView 上,一些網(wǎng)絡(luò)庫(kù)锦针,例如 OkHttp荠察,也是依賴 Http 緩存策略來(lái)進(jìn)行緩存數(shù)據(jù)的。

本文參加掘金技術(shù)征文:https://juejin.im/post/58d8e99261ff4b006cd6874d

公眾號(hào)二維碼.jpg
公眾號(hào)二維碼.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奈搜,一起剝皮案震驚了整個(gè)濱河市悉盆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馋吗,老刑警劉巖焕盟,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宏粤,居然都是意外死亡脚翘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門绍哎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)来农,“玉大人,你說(shuō)我怎么就攤上這事崇堰∥钟冢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)揽涮。 經(jīng)常有香客問(wèn)我抠藕,道長(zhǎng),這世上最難降的妖魔是什么蒋困? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任盾似,我火速辦了婚禮,結(jié)果婚禮上雪标,老公的妹妹穿的比我還像新娘零院。我一直安慰自己,他們只是感情好村刨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布告抄。 她就那樣靜靜地躺著,像睡著了一般嵌牺。 火紅的嫁衣襯著肌膚如雪打洼。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天逆粹,我揣著相機(jī)與錄音募疮,去河邊找鬼。 笑死僻弹,一個(gè)胖子當(dāng)著我的面吹牛阿浓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹋绽,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼芭毙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了卸耘?” 一聲冷哼從身側(cè)響起退敦,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鹊奖,沒(méi)想到半個(gè)月后苛聘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忠聚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年设哗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片两蟀。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡网梢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出赂毯,到底是詐尸還是另有隱情战虏,我是刑警寧澤拣宰,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站烦感,受9級(jí)特大地震影響巡社,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜手趣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一晌该、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绿渣,春花似錦朝群、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至淀散,卻和暖如春右莱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吧凉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工隧出, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阀捅。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像针余,于是被迫代替她去往敵國(guó)和親饲鄙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容