中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

WebView 緩存原理分析和應(yīng)用

2018-07-20    來(lái)源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

一、背景

現(xiàn)在的App開發(fā),或多或少都會(huì)用到Hybrid模式,到了WebView這邊,經(jīng)常會(huì)加載一些js文件(例如和WebView用來(lái)Native通信的bridge.js),而這些js文件不會(huì)經(jīng)常發(fā)生變化,所以我們希望js在WebView里面加載一次之后,如果js沒(méi)有發(fā)生變化,下次就不用再發(fā)起網(wǎng)絡(luò)請(qǐng)求去加載,從而減少流量和資源的占用。那么有什么方式可以達(dá)到這個(gè)目的呢?先得從WebView的緩存原理入手。

二、WebView的緩存類型

WebView主要包括兩類緩存,一類是瀏覽器自帶的網(wǎng)頁(yè)數(shù)據(jù)緩存,這是所有的瀏覽器都支持的、由HTTP協(xié)議定義的緩存;另一類是H5緩存,這是由web頁(yè)面的開發(fā)者設(shè)置的,H5緩存主要包括了App Cache、DOM Storage、Local Storage、Web SQL Database 存儲(chǔ)機(jī)制等,這里我們主要介紹App Cache來(lái)緩存js文件。

三、瀏覽器自帶的網(wǎng)頁(yè)數(shù)據(jù)緩存

1.工作原理

瀏覽器緩存機(jī)制是通過(guò)HTTP協(xié)議Header里的Cache-Control(或Expires)和Last-Modified(或 Etag)等字段來(lái)控制文件緩存的機(jī)制。關(guān)于這幾個(gè)字段的作用和瀏覽器的緩存更新機(jī)制,大家可以看看這兩篇文章(H5 緩存機(jī)制淺析 移動(dòng)端 Web 加載性能優(yōu)化,Android:手把手教你構(gòu)建 WebView 的緩存機(jī)制 & 資源預(yù)加載方案),里面有詳細(xì)的介紹。下面從我實(shí)際應(yīng)用的角度,介紹一下通常會(huì)在HTTP協(xié)議中遇到的Header。

這兩個(gè)字段是接收響應(yīng)時(shí),瀏覽器決定文件是否需要被緩存;或者需要加載文件時(shí),瀏覽器決定是否需要發(fā)出請(qǐng)求的字段。

  • Cache-Control:max-age=315360000,這表示緩存時(shí)長(zhǎng)為315360000秒。如果315360000秒內(nèi)需要再次請(qǐng)求這個(gè)文件,那么瀏覽器不會(huì)發(fā)出請(qǐng)求,直接使用本地的緩存的文件。這是HTTP/1.1標(biāo)準(zhǔn)中的字段。
  • Expires: Thu, 31 Dec 2037 23:55:55 GMT,這表示這個(gè)文件的過(guò)期時(shí)間是2037年12月31日晚上23點(diǎn)55分55秒,在這個(gè)時(shí)間之前瀏覽器都不會(huì)再次發(fā)出請(qǐng)求去獲取這個(gè)文件。這是HTTP/1.0中的字段,如果客戶端和服務(wù)器時(shí)間不同步會(huì)導(dǎo)致緩存出現(xiàn)問(wèn)題,因此才有了上面的Cache-Control,當(dāng)它們同時(shí)出現(xiàn)在HTTP Response的Header中時(shí),Cache-Control優(yōu)先級(jí)更高。

下面兩個(gè)字段是發(fā)起請(qǐng)求時(shí),服務(wù)器決定文件是否需要更新的字段。

  • Last-Modified:Wed, 28 Sep 2016 09:24:35 GMT,這表示這個(gè)文件最后的修改時(shí)間是2016年9月28日9點(diǎn)24分35秒。這個(gè)字段對(duì)于瀏覽器來(lái)說(shuō),會(huì)在下次請(qǐng)求的時(shí)候,作為Request Header的If-Modified-Since字段帶上。例如瀏覽器緩存的文件已經(jīng)超過(guò)了Cache-Control(或者Expires),那么需要加載這個(gè)文件時(shí),就會(huì)發(fā)出請(qǐng)求,請(qǐng)求的Header有一個(gè)字段為If-Modified-Since:Wed, 28 Sep 2016 09:24:35 GMT,服務(wù)器接收到請(qǐng)求后,會(huì)把文件的Last-Modified時(shí)間和這個(gè)時(shí)間對(duì)比,如果時(shí)間沒(méi)變,那么瀏覽器將返回304 Not Modified給瀏覽器,且content-length肯定是0個(gè)字節(jié)。如果時(shí)間有變化,那么服務(wù)器會(huì)返回200 OK,并返回相應(yīng)的內(nèi)容給瀏覽器。
  • ETag:”57eb8c5c-129”,這是文件的特征串。功能同上面的Last-Modified是一樣的。只是在瀏覽器下次請(qǐng)求時(shí),ETag是作為Request Header中的If-None-Match:"57eb8c5c-129"字段傳到服務(wù)器。服務(wù)器和最新的文件特征串對(duì)比,如果相同那么返回304 Not Modified,不同則返回200 OK。當(dāng)ETag和Last-Modified同時(shí)出現(xiàn)時(shí),任何一個(gè)字段只要生效了,就認(rèn)為文件是沒(méi)有更新的。

2.WebView如何設(shè)置才能支持上面的協(xié)議

由上面的介紹可知,只要是個(gè)主流的、合格的瀏覽器,都應(yīng)該能夠支持HTTP協(xié)議層面的這幾個(gè)字段。這不是我們開發(fā)者可以修改的,也不是我們應(yīng)該修改的配置。在Android上,我們的WebView也支持這幾個(gè)字段。但是我們可以通過(guò)代碼去設(shè)置WebView的Cache Mode,而使得協(xié)議生效或者無(wú)效。WebView有下面幾個(gè)Cache Mode:

  • LOAD_CACHE_ONLY: 不使用網(wǎng)絡(luò),只讀取本地緩存數(shù)據(jù)。
  • LOAD_DEFAULT: 根據(jù)cache-control決定是否從網(wǎng)絡(luò)上取數(shù)據(jù)。
  • LOAD_CACHE_NORMAL: API level 17中已經(jīng)廢棄,從API level 11開始作用同LOAD_DEFAULT模式
  • LOAD_NO_CACHE: 不使用緩存,只從網(wǎng)絡(luò)獲取數(shù)據(jù)。
  • LOAD_CACHE_ELSE_NETWORK,只要本地有,無(wú)論是否過(guò)期,或者no-cache,都使用緩存中的數(shù)據(jù)。本地沒(méi)有緩存時(shí)才從網(wǎng)絡(luò)上獲取。

設(shè)置WebView緩存的Cache Mode示例代碼如下:

WebSettings settings = webView.getSettings(); 
settings.setCacheMode(WebSettings.LOAD_DEFAULT); 

網(wǎng)上很多人都說(shuō)根據(jù)網(wǎng)絡(luò)條件去選擇Cache Mode,當(dāng)有網(wǎng)絡(luò)時(shí),設(shè)置為L(zhǎng)OAD_DEFAULT,當(dāng)沒(méi)有網(wǎng)絡(luò)時(shí)設(shè)置為L(zhǎng)OAD_CACHE_ELSE_NETWORK。但是在我的業(yè)務(wù)中,js文件的更新都是非覆蓋式的更新,也就是時(shí)候每次改變js文件的時(shí)候,文件的url地址一定會(huì)發(fā)生變化,所以我希望瀏覽器能夠緩存下來(lái)js,并且一直使用它,那么我就給它只設(shè)置為L(zhǎng)OAD_CACHE_ELSE_NETWORK。當(dāng)然如果你要是可以改js的cdn服務(wù)器的Cache-Control字段,那也行啊,用LOAD_DEFAULT就ok了。至于文件是應(yīng)該采用覆蓋式or非覆蓋式的更新,不是我今天要討論的內(nèi)容,在web前端領(lǐng)域,這是一個(gè)可以聊聊的topic。

關(guān)于iOS的WebView,我同事在實(shí)際測(cè)試的時(shí)候竟然發(fā)現(xiàn),控制文件緩存的Response Header是Expires字段。。而且iOS無(wú)法針對(duì)整個(gè)WebView設(shè)置Cache Mode,只能針對(duì)每一個(gè)URLRequest去設(shè)置。。后續(xù)有機(jī)會(huì)要學(xué)習(xí)一下iOS那塊的情況。

3.在手機(jī)里面的存儲(chǔ)路徑

瀏覽器默認(rèn)緩存下來(lái)的文件是怎么被存儲(chǔ)到了哪里呢?這個(gè)問(wèn)題在接觸到WebView以來(lái),就一直是一個(gè)謎題。這次由于工作的需要,我特意root了兩臺(tái)手機(jī),一臺(tái)紅米1(Android 4.4)和一臺(tái)小米4c(Android 5.1),在root高系統(tǒng)版本(6.0和7.1)的兩臺(tái)Nexus都以失敗告終之后,我決定還是先看看4.4和5.1系統(tǒng)上,WebView自帶的緩存存到了哪里。

首先,不用思考就知道,這些文件一定是在/data/data/包名/目錄下,在我之前的一篇博客里面提到過(guò),這是每一個(gè)應(yīng)用自己的內(nèi)部存儲(chǔ)目錄。

接著,我們打開終端,使用adb連接手機(jī),然后按照下面命令操作一下。

// 1.先進(jìn)入shell 
adb shell 
// 2.開啟root賬號(hào)  
su 
// 3.修改文件夾權(quán)限 
chmod 777 data/data/你的應(yīng)用包名/ 
// 4.修改子文件夾的權(quán)限,因?yàn)锳ndroid命令行不支持向Linux那樣的-R命令實(shí)現(xiàn)遞歸式的chmod。。。 
chmod 777 data/data/你的應(yīng)用包名/* 
// 5.所以如果你對(duì)應(yīng)用目錄層級(jí)更深,你就要進(jìn)一步地chmod。。。 
chmod 777 data/data/你的應(yīng)用包名/*/* 
// 6.直到終端里提示你說(shuō),no such file or directory時(shí),說(shuō)明chmod完了,所有的內(nèi)部存儲(chǔ)里面的文件夾和文件都可以看到了,如果大家有更好的方法請(qǐng)一定告訴我,多謝了~ 
  • Android 4.4的目錄:/data/data/包名/app_webview/cache/,如下圖所示的第二個(gè)文件夾。

可能你注意到了,第一個(gè)文件夾是叫Application Cache,我們后面再說(shuō)它。

  • Android 5.1的目錄:/data/data/包名/cache/org.chromium.android_webview/下面,如下圖所示。

但是在5.1系統(tǒng)上,/data/data/包名/app_webview/文件夾依然存在,只是4.4系統(tǒng)上面存儲(chǔ)WebView自帶緩存的app_webview/cache文件夾不再存在了(注意下App Cache目錄還在),如下圖所示。

綜上所述,WebView自帶的瀏覽器協(xié)議支持的緩存,在不同的系統(tǒng)版本上,位置是不一樣的。也許除了我root過(guò)的4.4、5.1以外,其他版本系統(tǒng)的WebView自帶緩存還可能存在于不同的目錄里面。

另外一個(gè)是關(guān)于緩存文件的存儲(chǔ)格式和索引格式,在不同的手機(jī)上可能也有差別,因?yàn)橹翱吹骄W(wǎng)上的人都說(shuō)有叫webview.db或者webviewCache.db的文件,這個(gè)文件呢,還不是在app_webview/cache或者org.chromium.android_webview下面,而是在/data/data/包名/database/里面。但是,我這兩臺(tái)root過(guò)的手機(jī)都沒(méi)有看到這種文件,而且我把/data/data/包名/下面所有的db文件都打開看了,并沒(méi)有發(fā)現(xiàn)有存儲(chǔ)url記錄的table。。

實(shí)際上,以5.1系統(tǒng)為例,我看到了/data/data/包名/cache/org.chromium.android_webview/下面有叫index和/index-dir/the-real-index的文件,以及一堆名稱為md5+下劃線+數(shù)字的文件,上面的圖中也可以看得到,這塊的原理仍然有些疑問(wèn),也希望專業(yè)的大神可以解答一下。

四、H5的緩存

講完了WebView自帶的緩存,下面講一下H5里面的App Cache。這個(gè)Cache是由開發(fā)Web頁(yè)面的開發(fā)者控制的,而不是由Native去控制的,但是Native里面的WebView也需要我們做一下設(shè)置才能支持H5的這個(gè)特性。

1.工作原理

寫Web頁(yè)面代碼時(shí),指定manifest屬性即可讓頁(yè)面使用App Cache。通常html頁(yè)面代碼會(huì)這么寫:

<html manifest="xxx.appcache"> 
</html> 

xxx.appcache文件用的是相對(duì)路徑,這時(shí)appcache文件的路徑是和頁(yè)面一樣的。也可以使用的絕對(duì)路徑,但是域名要保持和頁(yè)面一致。

完整的xxx.appcache文件一般包括了3個(gè)section,基本格式如下:

CACHE MANIFEST 
# 2017-05-13 v1.0.0 
/bridge.js 
 
NETWORK: 
* 
 
FALLBACK: 
/404.html 
  • CACHE MANIFEST下面文件就是要被瀏覽器緩存的文件
  • NETWORK下面的文件就是要被加載的文件
  • FALLBACK下面的文件是目標(biāo)頁(yè)面加載失敗時(shí)的顯示的頁(yè)面

AppCache工作的原理:當(dāng)一個(gè)設(shè)置了manifest文件的html頁(yè)面被加載時(shí),CACHE MANIFEST指定的文件就會(huì)被緩存到瀏覽器的App Cache目錄下面。當(dāng)下次加載這個(gè)頁(yè)面時(shí),會(huì)首先應(yīng)用通過(guò)manifest已經(jīng)緩存過(guò)的文件,然后發(fā)起一個(gè)加載xxx.appcache文件的請(qǐng)求到服務(wù)器,如果xxx.appcache文件沒(méi)有被修改過(guò),那么服務(wù)器會(huì)返回304 Not Modified給到瀏覽器,如果xxx.appcache文件被修改過(guò),那么服務(wù)器會(huì)返回200 OK,并返回新的xxx.appcache文件的內(nèi)容給瀏覽器,瀏覽器收到之后,再把新的xxx.appcache文件中指定的內(nèi)容加載過(guò)來(lái)進(jìn)行緩存。

可以看到,AppCache緩存需要在每次加載頁(yè)面時(shí)都發(fā)出一個(gè)xxx.appcache的請(qǐng)求去檢查manifest文件是不是有更新(byte by byte)。AppCache有一些坑的地方,且官方已經(jīng)不推薦使用了,但目前主流的瀏覽器依然是支持的。文章里主要提到下面這些坑:

  • 要更新緩存的文件,需要更新包含它的 manifest 文件,那怕只加一個(gè)空格。常用的方法,是修改 manifest 文件注釋中的版本號(hào)。如:# 2012-02-21 v1.0.0
  • 被緩存的文件,瀏覽器是先使用,再通過(guò)檢查 manifest 文件是否有更新來(lái)更新緩存文件。這樣緩存文件可能用的不是最新的版本。
  • 在更新緩存過(guò)程中,如果有一個(gè)文件更新失敗,則整個(gè)更新會(huì)失敗。
  • manifest 和引用它的HTML要在相同 HOST。
  • manifest 文件中的文件列表,如果是相對(duì)路徑,則是相對(duì) manifest 文件的相對(duì)路徑。
  • manifest 也有可能更新出錯(cuò),導(dǎo)致緩存文件更新失敗。
  • 沒(méi)有緩存的資源在已經(jīng)緩存的 HTML 中不能加載,即使有網(wǎng)絡(luò)。例如:[url=]http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/[/url]
  • manifest 文件本身不能被緩存,且 manifest 文件的更新使用的是瀏覽器緩存機(jī)制。所以 manifest 文件的 Cache-Control 緩存時(shí)間不能設(shè)置太長(zhǎng)。

2.WebView如何設(shè)置才能支持AppCache

WebView默認(rèn)是沒(méi)有開啟AppCache支持的,需要添加下面這幾行代碼來(lái)設(shè)置:

WebSettings webSettings = webView.getSettings(); 
webSettings.setAppCacheEnabled(true); 
String cachePath = getApplicationContext().getCacheDir().getPath(); // 把內(nèi)部私有緩存目錄'/data/data/包名/cache/'作為WebView的AppCache的存儲(chǔ)路徑 
webSettings.setAppCachePath(cachePath); 
webSettings.setAppCacheMaxSize(5 * 1024 * 1024); 

注意:WebSettings的setAppCacheEnabled和setAppCachePath都必須要調(diào)用才行。

3.存儲(chǔ)AppCache的路徑

按照Android SDK的API說(shuō)明,setAppCachePath是可以用來(lái)設(shè)置AppCache路徑的,但是我實(shí)際測(cè)試發(fā)現(xiàn),不管你怎么設(shè)置這個(gè)路徑,設(shè)置到應(yīng)用自己的內(nèi)部私有目錄還是外部SD卡,都無(wú)法生效。AppCache緩存文件最終都會(huì)存到/data/data/包名/app_webview/cache/Application Cache這個(gè)文件夾下面,在上面的Android 4.4和5.1系統(tǒng)目錄截圖可以看得到,但是如果你不調(diào)用setAppCachePath方法,WebView將不會(huì)產(chǎn)生這個(gè)目錄。這里有點(diǎn)讓我覺(jué)得奇怪,我猜測(cè)可能從某一個(gè)系統(tǒng)版本開始,為了緩存文件的完整性和安全性考慮,SDK實(shí)現(xiàn)的時(shí)候就吧AppCache緩存目錄設(shè)置到了內(nèi)部私有存儲(chǔ)。

五、總結(jié)

相同點(diǎn)

WebView自帶的緩存和AppCache都是可以用來(lái)做文件級(jí)別的緩存的,基本上比較好地滿足對(duì)于非覆蓋式的js、css等文件更新。

不同點(diǎn)

  • WebView自帶的緩存是是協(xié)議層實(shí)現(xiàn)的(瀏覽器內(nèi)核標(biāo)準(zhǔn)實(shí)現(xiàn),開發(fā)者無(wú)法改變);而AppCache是應(yīng)用層實(shí)現(xiàn)的。
  • WebView的緩存目錄在不同系統(tǒng)上可能是不同的;而對(duì)于AppCache而言,AppCache的存儲(chǔ)路徑雖然有方法設(shè)置,但是最終都存儲(chǔ)到了一個(gè)固定的內(nèi)部私有目錄下。
  • WebView自帶的緩存可以在緩存生效的時(shí)候不用再發(fā)HTTP請(qǐng)求;而AppCache一定會(huì)發(fā)出一個(gè)manifest文件的請(qǐng)求。
  • WebView自帶的緩存可以通過(guò)設(shè)置CacheMode來(lái)改變WebView的緩存機(jī)制;而AppCache的緩存策略是由manifest文件控制的,也就是說(shuō)是由web頁(yè)面開發(fā)者控制的。

最后說(shuō)一下,其實(shí)很多時(shí)候,這兩類緩存是共同在工作的,當(dāng)manifest文件沒(méi)有控制某些資源加載時(shí),例如我上面寫的xxx.appcache文件里,NETWORK section下面用的是*號(hào),意思是所有不緩存的文件都要去網(wǎng)絡(luò)加載。此時(shí),這些資源就會(huì)走到WebView自帶的緩存機(jī)制去,結(jié)合WebView的CacheMode,我們實(shí)際上對(duì)這些文件進(jìn)行了一次WebView自帶的緩存。搞清楚這兩類緩存的原理有利于我們更好的設(shè)計(jì)自己的頁(yè)面和App,盡可能減少網(wǎng)絡(luò)請(qǐng)求,提高App運(yùn)行效率。

 

來(lái)自:http://mobile.51cto.com/android-539935.htm

 

標(biāo)簽: linux 安全 代碼 服務(wù)器 開發(fā)者 權(quán)限 通信 網(wǎng)絡(luò) 域名

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:提高Rails開發(fā)者編碼效率的實(shí)用小貼士

下一篇:不簡(jiǎn)單的前端性能優(yōu)化