Android WebView的默認緩存策略

導讀

本文作者:choha

發佈時間:2020-02-06

原文地址:https://www.jianshu.com/p/4e5049101271

做了2年混合開發了,經常和WebView打交道,對於瀏覽器的緩存策略也瞭解啦!但是默認緩存策略還真得沒去了解過。意外看到這篇文章,很驚喜。話不多說,咱們來看看吧!


1. 背景

今天測試反饋,前端更新了H5的內容,但是客戶端通過webview的方式打開後,發現內容沒有更新,使用charles抓包,發現客戶端訪問訪問時,連請求都沒法發出。於是測試的妹子在企業微信中@我,看到消息有點懵,記得去年就排查過webview的緩存方式,怪沒有記錄,今天決定把問題重新記錄一下。

2. webview的緩存方式

先上代碼:

WebSettings settings = webView.getSettings();
settings.setDomStorageEnabled(true); // 開啓 DOM storage API 功能
settings.setDatabaseEnabled(true); // 開啓 DB storage API 功能
settings.setAppCacheEnabled(true); // 開啓 AppCacheEnable

// 設置緩存模式,非常重要,決定了webview緩存資源的方式
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

我們重點關注setCacheMode方法緩存模式,系統提供了5種緩存模式,其中一種已經LOAD_CACHE_NORMAL在新版本中廢棄:

  • LOAD_CACHE_ONLY: 不髮網絡請求資源,只讀取緩存。
  • LOAD_DEFAULT: 根據cache-control或者Last-Modified決定是否從網絡上取數據。默認採用該方案
  • LOAD_CACHE_NORMAL: 新版本已經廢棄,同LOAD_DEFAULT
  • LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據。
  • LOAD_CACHE_ELSE_NETWORK:只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。本地沒有緩存時才從網絡上獲取。

大家都知道,webview是一個瀏覽器,且在4.4以下版本,都是採用WebKit作爲內核,4.4以上採用Chrome作爲內核。既然是瀏覽器,且又是緩存,那我們就有必要引入Http協議中的緩存,因爲瀏覽器是對Http協議最基本的執行者,且瀏覽器的緩存原理,都是對Http協議的緩存做了基本且標準的支持(可能瀏覽器有擴展,但是都兼容Http基礎協議)

3. HTTP協議緩存

我們這裏只介紹幾個常用的緩存header,詳細的大家可以度娘Http協議相關。

Http協議常用的緩存header有:

Cache-Control:Cache-Control是非常最重要的規則,主要用於控制網頁緩存。比如當Cache-Control:max-age=30時,在表示資源正確加載後,30s內重新請求,不在重新發網絡請求,直接使用本地資源。cache-control可以配置很多規則,這裏介紹幾種常用的:

【max-age = xx】:在客戶端緩存xx秒,過了xx秒後,重新請求資源,但是這個另外一個Etag或last-modified有關係,如果服務端跟進Etag判斷文件沒有修改,則返回304,這是還是使用緩存,如果返回200,則說明資源跟新了,瀏覽器正常從網絡加載資源

【s-maxage = xx】:作用同max-age,但是會覆蓋max-age,不過他只有在代理服務器中生效

【no-store】:不緩存任何資源

【no-cache】:資源會緩存,表示必須先與服務器確認返回的響應是否發生了變化,然後才能使用該響應來滿足後續對同一網址的請求

Expires:具體時間,例如Expires:Tue,25 Sep 2018 07:17:34 GMT, 這表示這個文件的過期時間是格林尼治時間2018年9月25日7點17分。因爲我是北京時間2018年8月26日15點請求的, 所以可以看出也是差不多一個月有效期。在這個時間之前瀏覽器都不會再次發出請求去獲取這個文件。Expires是HTTP/1.0中的字段,如果客戶端和服務器時間不同步會導致緩存出現問題,因此纔有了上面的Cache-Control。當它們同時出現時,Cache-Control優先級更高。

Etag:文件的一個標識,可以理解爲MD5

Last-Modified:文件最後修改時間。

總結:瀏覽器就是跟進上述緩存邏輯,對資源進行緩存,當然了,緩存業務不僅僅這麼簡單,還是非常複雜的,有興趣的可以查看HTTP協議和瀏覽器內核。

4. 解決我遇到的問題

問題現象】:服務器的H5內容更新了,但是客戶端卻更新不到,且沒有發請求。

問題原因猜想】:猜想android 系統的Webview做了緩存策略,導致在緩存有效期,不發請求。

既然我們已經猜想了問題原因,那就需要順着這個思路排查該H5的緩存策略配置是什麼:

這是抓包看到請求Http response的Header內置,發現只有ETag和Last-Modified,並沒有配置Cache-Control,那問題來了,如果沒有配置Cache-Control,那麼瀏覽器的緩存策略是什麼呢?通過一番折騰,終於找到了瀏覽器默認的緩存策略,這個緩存策略叫做:啓發式算法,原理是:

通過採用請求響應頭中的Date減輕Last-Modified的值的10%作爲緩存時間,即在這10%的時間內不發請求。直接使用緩存資源。

通過驗證,發現webview的默認緩存策略,確實如此。我們的問題頁定位到了。既然定位了,就好解決。

5. 解決方案

① 服務端添加cache-control 的方式,這裏我們配置的是max-age = 24*60*60(一天),需跟進自己的業務處理。

② 也可以配置爲no-cache,但是可能增加服務端的請求量,需要跟進自己的業務更新頻率配置。

 

如果想進一步交流和學習的同學,可以加一下QQ羣哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章