记录如何优化Webview缓存更新问题

1,613 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情

前言

webview页面加载过之后,修改页面数据,重新发布刷新CDN,但客户端中的webview无论是刷新还是重进,都没有更新,重启App也无法更新,除非手动清除web缓存,或者重装App才能更新为最新页面。

分析

猜测大概率是webview的缓存导致的,非首次加载大部分静态资源都是 (disk cache)

image.png

通过某度学习了一下,webview的缓存可分为:客户端缓存服务端缓存

服务端缓存一般就是CDN缓存,这个一般发布之后都会自动或主动进行刷新,所以大概率不是服务端缓存的问题。

客户端缓存机制如下

CacheMode {

    // 如果页面没有强制任何特定行为(依赖服务端控制),如果本地有未过期的缓存,就会直接加载本地缓存,否则就请求网络

    LOAD_DEFAULT = -1

    // 从API 11开始就废弃了,和LOAD_DEFAULT行为一致

    LOAD_NORMAL = 0

    // 只要本地有缓存,不管有没有过期,都使用本地缓存。否则就请求网络

    LOAD_CACHE_ELSE_NETWORK = 1

    // 忽略本地缓存(就算有也不用),直接请求网络

    LOAD_NO_CACHE = 2

    // 只使用本地缓存,不请求网络

    LOAD_CACHE_ONLY = 3

}

默认是LOAD_DEFAULT依赖服务器配置的缓存策略。

那么如何可以控制客户端的缓存呢?

hash码命名打包

搜到的一个很常见的方案是:使用hash码编码打包,每次更改文件之后hash码改变,使文件名改变,从而达到欺骗浏览器url变动了,就不会使用之前的缓存,而使用最新的文件。

但有个问题,不同的项目有不同的习惯和规定嘛,一般多个项目会有通用的模块,常用的共用的方法会从这里面获取,而我们又不是整体打包的,我们只会更新需要更新的项目。那通用模块的改动导致了文件名的变更,那就会影响所有的调用了通用模块的项目,这些项目都得重新打包发布,影响较多。

还有index.html也无法更改文件名,会导致主url改变,假如是用index.html的方式的话。(不过我也不确定index.html变不变会不会影响缓存)。

综上,我使用了类似的优化方案,就是在每个路径之后,拼接上?v=hashCode,使用glue实现。最终效果如下

image.png

然后测试了一下,emmm,还是一样,更新发布之后,数据还是没有及时更新,看看Network的加载,index.html的内容还是旧的,所以还是请求的旧的css和js

image.png

那好吧,在请求时,自动拼接上每次都不一样的uuid试一下。失败,还是请求的相同的资源。

image.png

难道拼接hashCode的方法对于index.html并不能生效?

不知道是姿势不对还是方式不对,反正在尾巴加上hashCode的方案经过尝试貌似并不能解决缓存问题。

设置Cache-Control的缓存有效时间

分析时我们知道客户端缓存策略默认LOAD_DEFAULT,这是依赖服务端配置的缓存策略,意思就是可以由服务端来控制客户端的缓存配置

经研究,可以设置Cache-Control来配置缓存的属性。

image.png

那具体怎么操作呢?查了下firebase-hosting的配置,可以在firebase.json中的headers中增加Cache-Control,并加入自定的配置。若没有设置的话,默认是60分钟,60分钟才会失效,获取新的资源。

image.png

更改为60sdeploy,测试一下。首次加载之后,等待一分钟,再重新加载,成功了!页面成功更新为最新的数据!

然后看了下AWS的,也可以在里面配置缓存策略,默认是24小时,所以使用AWS默认要等待24个小时才能更新为新的数据,属实是久了点,可以更改为一个合适的时间。

综上

webview的内容不能及时更新,主要是客户端缓存导致的,虽然网上有很多hashCode编码来”欺骗“浏览器的方式,但实际效果不太好(也不知道是不是操作没对)。

可以考虑通过服务器的配置(Cache-Control)来设置客户端缓存的有效时间,适当的设置可以让数据及时的更新,但时间也不要太短,不然就失去了缓存的意义,一般根据场景,我认为5分钟到半小时是比较好的。

还有一种方式就是使用Http Server本地加载,不使用webview缓存,自己来控制缓存,假如能通过下发的方式通知客户端对应web来更新资源,那更新和加载的体验会更好(仅App的)。

webview的本地加载有兴趣可以看看我之前的文章。