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群哦!

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