阅读 533

Android WebView缓存没更新解决方案

一:现象

  1. 客户端加载过H5页面A,后来H5修改为A'发布之后,在很长一段时间内,客户端一直展示的是A,没有更新为A'。
  2. 重启之后依然没有更新,只有清除缓存或者重装APP才会更新。

二:分析

根据现象得出,是由于webview的缓存导致页面一直没有更新。但是为什么没有更新?更新的机制是什么?应该怎么修改?

首先看下客户端的缓存机制,CacheMode一共有五种

    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模式,这个是依赖服务端配置的缓存策略

http协议缓存机制

http协议缓存机制是指通过 HTTP 协议头里的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等字段来控制文件缓存的机制。

Expires 是 HTTP1.0 标准中的字段,Cache-Control 是 HTTP1.1 标准中新加的字段,功能一样,都是控制缓存的有效时间。当这两个字段同时出现时,Cache-Control 是高优化级的。

Cache-Control参数可参考 浅谈http中的Cache-Control

三:解决方案

客户端:CacheMode使用LOAD_DEFAULT即可,依赖服务端控制缓存策略。为了解决线上版本缓存有效期时间过长的问题,可以在请求的url后面加无效参数,例如#,欺骗浏览器url变动,强制浏览器去服务器更新一次。

服务端:修改nodejs express服务,设置静态资源的时候设置了下这个Cache-Control属性。修改方式可参考 Express 中设置缓存Cache-control的maxAge

服务器配置:Nginx服务器配置Cache-Control也是可行的。

缓存策略需要根据具体业务来确定,如果该页面没有要求实时更新,可以使用max-age=XX来控制,在再XX秒时间范围内使用缓存,否则就请求网络。

四:测试流程

使用max-age=60验证页面更新情况

  1. 前提,清除缓存,服务端先加上max-age属性
  2. 客户端先进入页面缓存一次。
  3. h5修改资源发布
  4. 客户端再60秒之内打开页面,没有更新,60秒之后再次打开,页面正常更新。

五:注意事项

  1. 如果之前服务端没有加任何控制缓存的参数(Cache-Control),客户端缓存了该H5页面,此时修改服务端缓存策略,客户端在缓存过期之前是不会重新请求资源的。必须等到客户端缓存过期,或者清除缓存才可以。
  2. HTML头部添加
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
复制代码

并没有生效,被忽略了

  1. 在服务端没有配置任何缓存策略时,Android缓存有效期时间会很长,也就是长时间不会更新。而iOS每次进入页面都会更新,由于iOS和Android内核不一样,iOS是Safari,Android是chromium,处理方式可能会有差异。
  2. 在服务端没有加任何控制缓存的参数情况下,使用pc端浏览器打开H5,在H5修改之后,谷歌浏览器也是没有立即更新的,必须使用强制刷新(Shift+F5),但是火狐浏览器F5就可以正常刷新了。谷歌浏览器和Android内置浏览器都是chromium内核,表现基本一致。
  3. 查看网页响应头
    浏览器打开该网页,按F12,选择Network,然后再刷新下网页,选择左下栏第一个.html的页面,右面的Headers里面可以看到Cache-Control,说明服务端配置生效了。

参考:

H5 和移动端 WebView 缓存机制解析与实战