H5被某些特殊手机强制缓存导致发布新版本始终无法生效的问题

TOC

碰到的问题

  1. 某些手机上始终打开的都是旧版本H5
  2. 重启APP + 重启手机都无效
  3. 卸载APP + 清空APP数据能生效

目的:将H5每次使用的是哪个版本留在历史日志记录里

方便排查问题时, 清晰的知道当时用的H5模块是不是最新的版本
看看是不是真的存在强制缓存的情况

思考方案1

index.html 每次发布新的时候就修改为最新的版本
增加版本号 v0224-1a214b6b324d 发布目录
最终形成以下目录结构:
a.dist
->index.html(可能被强制缓存的情况下如何处理?)

调用location.replace或者azyk.loadUrl

->v0224-1a214b6b324d
->->index.html
->->static
->->js

->v0223-abcdfqeess24d
->->index.html
->->static
->->js
就是需要H5发布的脚本需要改造.
后续要是真碰到强制缓存的情况, 再使用方案2来辅助?

思考方案2

->index.html(可能被强制缓存的情况下如何处理?)

通过数据同步 强制替换目标路径 到 v0224-1a214b6b324d/index.html ?
直接修改H5;菜单配置表的链接即可!这样数据同步后百分百能解决问题

  1. 增加新推送指令, 让用户下次重新登录, 只刷新菜单表表 即可.

思考方案3

H5的发布 和 APP发布一个流程, 需要上传压缩包到OSS, 然后APP直接按版本号访问OSS?
或者直接下载压缩包, 直接本地访问H5
通过数据同步,可以达到百分百替换H5的效果,避开缓存.
就是需要额外的下载,解压缩 处理逻辑

最终方案4(已上线待验证)

  • 将index.html页面进行JS脚本改造
  • 假设的极端情况就是index.html也被缓存的情况下
  • 使用JS发起HEAD请求自身,将状态记录到缓存里,发现不一样时强制刷新自身
    • If-Modified-Since: Mon, 21 Mar 2022 12:40:04 GMT
    • If-None-Match: "38b0edc9203dd81:0"
  • 强制刷新的方式,不知道以下哪种方式会生效??
    • location.reload || location.reload(true)
    • azyk.reload()
    • location.query += date.now()
    • 获取通过XHR直接将index.html GET请求下来(会触发缓存吗?), 然后直接替换 html.outHtml ?
  • 假设网络不好HEAD请求耗时几秒, 此时用户正在正常使用H5,此时突然强制刷新,体验会不好,是否可以考虑打个标记,然后在下次进入时发现第一个脚本的.hash码不一直时,再强制刷新? 同时免除本次刷新
    • 先看是否有标记,
      • 有则强制刷新
      • 没有则触发异步刷新,并正常显示
        • 主脚本HASH不一致则记录一个标记
        • 一致时则无需其它动作
<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <title>
            <%= htmlWebpackPlugin.options.title %>
        </title>
        <script>
            var eTag = localStorage.getItem('ETag');
            if (eTag && eTag.length > 0 && location.search.indexOf(eTag) == -1) {
                console.log('添加ETag并重载中')
                location.search = 'ETag=' + eTag;
            } else {
                var r = new XMLHttpRequest();
                r.open("HEAD", location.origin + location.pathname + '?t=' + new Date().getTime());
                r.onload = function(e) {
                    var newETag = this.getResponseHeader("ETag");
                    newETag = encodeURIComponent(newETag.replace(/[^\w]/g, ''));
                    if (eTag != newETag) {
                        console.log('ETag已变(下次生效)=' + newETag + '; Old=' + eTag);
                        localStorage.setItem('ETag', newETag);
                    } else
                        console.log('ETag未变')
                }
                r.send();
                var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' &&
                    (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
                document.write(
                    '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
                    (coverSupport ? ', viewport-fit=cover' : '') + '" />')
                document.write('<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />')
            }
        </script>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

相关笔记

参考资料

  1. 解决 Web 缓存的 Python 脚本 - SegmentFault 思否 https://segmentfault.com/a/1190000021262100
  2. 获取最后修改日期 | MDN https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#%E6%9C%80%E5%90%8E%E4%BF%AE%E6%94%B9%E6%97%A5%E6%9C%9F%E6%94%B9%E5%8F%98%E5%90%8E%E7%9A%84%E6%93%8D%E4%BD%9C
  3. 绕过缓存 | MDN https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#%E7%BB%95%E8%BF%87%E7%BC%93%E5%AD%98
posted @ 2022-06-29 22:38  Asion Tang  阅读(546)  评论(0编辑  收藏  举报