V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kongkongye
V2EX  ›  前端开发

前端重新部署后如何让用户刷新页面?

  •  
  •   kongkongye ·
    kongkongye · 2022-05-26 19:08:18 +08:00 · 6658 次点击
    这是一个创建于 672 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前碰到的情况是前端重新构建部署后,js 之类文件名都变了,前端点击另一个页面就白屏(控制台报错 js 文件找不到),而很多用户比较小白就会反馈页面出问题了而不是刷新页面。
    所以想着重新部署后应该通知到用户应该刷新前端页面,目前能想到的方式是所有请求都自动加上前端当前版本,通过工具重新构建后通知后端修改前端最新版本号,然后前端页面请求时就能返回信息让前端提示页面需要刷新,不知有没更好的办法?

    50 条回复    2022-07-04 10:35:57 +08:00
    kongkongye
        1
    kongkongye  
    OP
       2022-05-26 19:09:57 +08:00 via iPhone
    不知道大厂都是怎么解决这个问题的,像我们企业内部系统,可能一天发布几次前端更新,就很容易碰到这种情况。
    ksc010
        2
    ksc010  
       2022-05-26 19:11:31 +08:00
    简单的方法就是 捕获异常 然后弹窗提示需要刷新重拾下
    yunye
        3
    yunye  
       2022-05-26 19:11:44 +08:00   ❤️ 3
    Vue 项目部署新版本后怎么提示用户刷新浏览器?
    https://segmentfault.com/q/1010000039658752/

    service-worker 服务端单方面强制刷新客户端(浏览器)缓存
    https://www.0z.gs/webDevelopment/1375.html

    参考一下吧
    westoy
        4
    westoy  
       2022-05-26 19:13:20 +08:00
    我之前一个简单的类 CRM 是直接维护一个 websocket, 下发各种刷新 settings 、语言包的命令, 不过用的人少, 一般也就在线个几十个.......

    你可以考虑 window.onerror 捕捉错误, 看情况 fetch 一个最新版本, 版本落后就强制 reload
    kongkongye
        5
    kongkongye  
    OP
       2022-05-26 19:14:15 +08:00 via iPhone
    @ksc010 我的意思就是这个,就是现实很少碰到过这种情况,想着一般都是一个网页用完就关,出问题就刷新,都不知大厂在这个问题上有没考虑过,不好参照
    dcsuibian
        6
    dcsuibian  
       2022-05-26 19:14:37 +08:00 via Android
    更新版本的时候,把之前的 js 都删掉了?
    emonc
        7
    emonc  
       2022-05-26 19:14:56 +08:00
    🤔用路由守卫怎么样?
    kongkongye
        8
    kongkongye  
    OP
       2022-05-26 19:15:08 +08:00 via iPhone
    @westoy 不喜欢 ws ,感觉不稳定容易断,还占服务器资源
    kongkongye
        9
    kongkongye  
    OP
       2022-05-26 19:18:36 +08:00 via iPhone
    @westoy 也不喜欢强制 reload ,没提示话用户会觉得莫名奇妙页面刷新了
    kongkongye
        10
    kongkongye  
    OP
       2022-05-26 19:19:25 +08:00 via iPhone
    @westoy 或者比如用户在填表单,你给强制 reload 了。。。
    ksc010
        11
    ksc010  
       2022-05-26 19:19:48 +08:00
    @kongkongye 这个方法 我感觉是最简单 前端加几行代码就搞定了
    监听全局异常错误,然后也可以再判断下异常类型啥的,就因为很少遇到,我感觉稍微弄下就行
    estk
        12
    estk  
       2022-05-26 19:19:50 +08:00
    旧的 js 我都一直保留,这样哪怕用户缓存了,至少还能访问旧版
    kongkongye
        13
    kongkongye  
    OP
       2022-05-26 19:21:41 +08:00 via iPhone
    @estk 清了节省空间,看着清净,毕竟不是访问量很大的项目,没考虑这
    hmm1225
        14
    hmm1225  
       2022-05-26 19:58:36 +08:00
    你 html 文件不缓存不就可以了
    makelove
        15
    makelove  
       2022-05-26 21:45:33 +08:00
    打包时生成版本号至应用 js ,应用里写个定时每隔 1 分钟调用后端接口发现当前版本不是最新就提示刷新
    wenzichel
        16
    wenzichel  
       2022-05-26 22:23:06 +08:00
    刚看描述不明白为什么会出现白屏,原来是把旧的静态资源删除了,这不应该啊。你的静态资源应该增量更新啊,每次发布的静态资源都带有 hash ,发布到 CDN 上。

    如果实在是想节省空间,那就单独跑脚本,比如每隔一星期定期进行清理,相同名字的静态资源,只保留最近 30 天的,若只剩下 1 个,就不再删除。

    但我还是建议您把静态资源发布到 CDN 上!
    wenzichel
        17
    wenzichel  
       2022-05-26 22:26:00 +08:00
    所以你的方案不应该放在如何让用户强制刷新页面,而是如何进行增量更新。

    若 html 没有过期,依然访问的是旧资源,等 html 过期了,自然访问的就是新资源了。
    bojackhorseman
        18
    bojackhorseman  
       2022-05-26 22:55:01 +08:00 via iPhone
    @wenzichel 我目前也遇到这个问题,以前部署是直接把文件通过 sftp 上传上去的,现在每次部署都是打包后的产物打一个镜像推到 docker 仓库里,这样就没法增量更新了吧。
    Vegetable
        19
    Vegetable  
       2022-05-26 23:04:30 +08:00
    1. 不要立刻清除旧的资源
    2. 提示用户有更新,请刷新页面

    其实就是把网页当作客户端对待嘛,至于实现更新提醒,方法挺多的。随便说一个不一定行得通,本地记录页面初始化的时间,前端 1 分钟 head 一次 index.html ,判断 Last-Modified
    arischow
        20
    arischow  
       2022-05-26 23:05:09 +08:00
    静态资源不随着新版本发布而删除
    gouflv
        21
    gouflv  
       2022-05-27 00:24:03 +08:00 via iPhone
    典型的 没找到原因就开始想解决方案
    bjfane
        22
    bjfane  
       2022-05-27 02:18:49 +08:00
    哈哈哈,好巧,这是我面试题库里的题之一,我的方案是路由守卫里加实现,做法也很简单,/version.json 是发布时候的一个时间戳 - {202205234345564},beforeRoute 里有动作就请求 /version.json?{random},和当前程序里的 version 不一致就提示 并自动刷新

    ws 和轮训都不太行,开销太大。
    Puteulanus
        23
    Puteulanus  
       2022-05-27 02:36:32 +08:00
    我们是用的 ws ,脚本是在 nginx 里用 replace 直接注入到页面 html 里的,所以只有测试环境有,打开页面的时候会建一个到通知服务的连接,然后 pipeline 上一旦重新部署了会调一下通知服务,对所有当前连接用户广播一个通知过去

    那种页面挂后边挺长时间甚至出门吃了个饭 ws 已经断了太久的,就给个提示说网页可能不是最新了

    当时的需求是 QA 说可能测试环境布了新版本他们不知道,测出来的还是老版本前端的 bug ,特别是有了零停机部署之后,部署过程中服务是完全不中断的,所以做了个通知给当前正在使用网页的人
    aaronlam
        24
    aaronlam  
       2022-05-27 06:11:43 +08:00 via iPhone
    anguiao
        25
    anguiao  
       2022-05-27 07:52:28 +08:00
    你这个需求的话,不缓存 HTML (或者协商缓存),只缓存静态文件,不就行了么。
    静态文件的文件名都是带 hash 的,只要 HTML 更新了,这些静态文件也会跟着更新。

    我是用 nginx 的 request_filename 来做的,目前用下来没发现有什么问题。
    zhuwd
        26
    zhuwd  
       2022-05-27 08:25:05 +08:00
    @bjfane 这个方案是不是相当于每次路由跳转都要拉一下 version.json 文件?
    ChefIsAwesome
        27
    ChefIsAwesome  
       2022-05-27 08:37:16 +08:00   ❤️ 1
    动态加载 js 文件时会出现这种问题。最常见的就是做 spa ,并且每个路由的 js 是动态加载的。因为 { /path: xx.js } 这个是写在最初访问网页时下载的 js 里的。而 spa 切换页面时不会重新下载 html ,也就不会重新下载最初的 js 。
    实际上这个问题等同于后端接口升级了,用旧版本客户端的人要怎么办。
    原生应用一般就是保留旧版本的资源,再加一个检查版本,提示升级的功能。
    网页跟原生应用不一样,不存在死守着旧版本不放的情况。保留一个旧版本就行了。
    sugars
        28
    sugars  
       2022-05-27 08:42:45 +08:00
    @anguiao 他的意思是不刷新页面啊,你这个不还得去刷新页面才能重新访问 index.html
    anguiao
        29
    anguiao  
       2022-05-27 08:52:48 +08:00
    @sugars 确实,欠考虑了。
    lower
        30
    lower  
       2022-05-27 09:26:40 +08:00
    @kongkongye 层主不是说了,在 error 的时候处理么,都 error 了,随便提示个网络连接异常啥的把用户哄过去……
    DOLLOR
        31
    DOLLOR  
       2022-05-27 09:27:00 +08:00
    (await fetch(`./index.html?nocache=${Date.now()}`)).headers.get('last-modified')
    cloverstd
        32
    cloverstd  
       2022-05-27 09:35:36 +08:00
    你的问题是发布后,老的页面的 js 没法访问了,增量发布就行,不要删除老的文件,反正静态资源文件名有 hash
    lerry
        33
    lerry  
       2022-05-27 09:36:23 +08:00
    1. 可以不删除旧的资源文件避免报错
    2. 打包时加入一个版本号,定时检测

    "build": "vue-cli-service build && npm run update-version",
    "update-version": "mkdir -p dist && echo `date +%s` > dist/version.txt"

    设置一个定时器,检查版本号有没有变化,弹窗提示 reload
    await fetch(`/version.txt?timestamp=${Date.now()}`);
    hevi
        34
    hevi  
       2022-05-27 09:36:29 +08:00
    下班的时候更新呗,又不愿意用 websocket 。
    ~~js 名字匹配重定向,曲线救国~~
    wanguorui123
        35
    wanguorui123  
       2022-05-27 10:13:04 +08:00
    缓存设置短点 1 小时过期,开启 302 ETag 检查
    bjfane
        36
    bjfane  
       2022-05-27 11:42:28 +08:00
    @zhuwd 是的,一个静态文件,但是内容很短
    kongkongye
        37
    kongkongye  
    OP
       2022-05-27 12:20:39 +08:00 via iPhone
    @lerry 我最后思考出的解决方案几乎跟你这一致
    lizy0329
        38
    lizy0329  
       2022-05-30 18:45:32 +08:00
    你傻啊,发布代码为什么要将之前的文件删掉?要做到非覆盖式发布,而不是覆盖式发布
    a570295535
        39
    a570295535  
       2022-06-01 22:02:05 +08:00
    你可以在页面上写个 js 判断调用的 js 是否加载成功,成功就忽略,没成功就提醒用户,现在网页升级了,你是否刷新一下,不刷新就给老子滚!
    a570295535
        40
    a570295535  
       2022-06-01 22:57:40 +08:00
    把这句加到其他 js 的前面:
    <script type="text/javascript">window.addEventListener('error',function(){document.write("出错了二逼,<a href=\"javascript:location.reload();\">给爷刷新</a>");},true);</script>
    WenJimmy
        41
    WenJimmy  
       2022-06-02 16:36:41 +08:00
    和 22 楼一样
    生产构建的时候生成一个 version.json 一并发布到网站目录,在路由守卫和接口请求前检查根目录 json 内容,不一致就提醒更新
    coolzjy
        42
    coolzjy  
       2022-06-09 22:45:01 +08:00
    1. 所有资源上传 OSS 保留历史版本
    2. 使用 MPA ,切换页面直接请求新的 html
    3. 不使用 code splitting ,所有页面打成一个包

    加版本、每次检查、提示刷新这套方案不管从技术上还是从用户角度都太不友好了。
    ymcz852
        43
    ymcz852  
       2022-06-15 11:17:28 +08:00
    @wenzichel 大佬,不好意思打扰了,想问下按照你这种方案的话,具体是怎么操作呢?每次打包都会生成新的 html 和 js 等静态资源的包,那么 oss 上就会有新的 A 包和旧的 B 包,cdn 那个地址要如何指向新的 A 包里的 html 呢?是要用先访问 Ngnix 的地址,然后指向 cdn 里的新的 A 包里的 html 吗?
    wenzichel
        44
    wenzichel  
       2022-06-15 14:24:25 +08:00   ❤️ 1
    @ymcz852 我们这里,是 html 页面和 js 等静态资源都是发到 CDN 上,只不过 html 页面的过期时间会短一点( 5 分钟左右)。为保证访问的链接不变,html 发布是固定的名字,而 js 等资源就是 hash 的增量更新。无论用户访问是之前旧的 html ,还是发布的最新的 html ,都有其对应的静态资源。

    我想,没有哪个业务可以极端到在发布新包后,一定要让用户在第一时间更新到最新的文件。

    旧 html 里访问的是旧的静态资源,新 html 就访问新的 html 资源。等用户的旧 html 页面缓存过期了,就自动访问新的 html 页面了,就可以了。

    当然,如果一定在发布后,所有用户都访问最新的资源,那就模仿游戏里的“停机维护”。在发布之前,所有的访问都导向到维护页面,等发布完成后,再把流量导过来。
    ymcz852
        45
    ymcz852  
       2022-06-15 15:34:52 +08:00
    @wenzichel `为保证访问的链接不变,html 发布是固定的名字`请问这里是如何操作的,如何通过固定的链接访问到不同的包里的 html 呢?
    ImmerTry
        46
    ImmerTry  
       2022-06-27 15:56:47 +08:00
    @DOLLOR 请教一下,这段代码添加到哪个文件上啊
    GreatAuk
        47
    GreatAuk  
       2022-06-28 23:20:16 +08:00
    因为前端项目是容器部署,不知道怎么做增量更新,所以自己写了个打包插件 https://github.com/GreatAuk/plugin-web-update-notification ,通知用户刷新页面。楼上用打包时间当版本号的想法也不错,我到时也加下这个功能😁。
    ImmerTry
        48
    ImmerTry  
       2022-07-02 12:09:16 +08:00
    @lerry 那本地在获取到的时候 是不是要存进 session storage 里面去啊
    lerry
        49
    lerry  
       2022-07-02 13:41:34 +08:00
    @ImmerTry #48 存变量就行
    ImmerTry
        50
    ImmerTry  
       2022-07-04 10:35:57 +08:00
    @lerry 好的,谢谢,还有一点就是每次上包的时候是覆盖更新,还是要把旧的删除掉在换包
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3010 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:57 · PVG 22:57 · LAX 07:57 · JFK 10:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.