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

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

  •  
  •   kongkongye ·
    kongkongye · 126 天前 · 3251 次点击
    这是一个创建于 126 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

    参考一下吧
    westoy
        4
    westoy  
       126 天前
    我之前一个简单的类 CRM 是直接维护一个 websocket, 下发各种刷新 settings 、语言包的命令, 不过用的人少, 一般也就在线个几十个.......

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

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

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

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

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

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

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

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

    我是用 nginx 的 request_filename 来做的,目前用下来没发现有什么问题。
    zhuwd
        26
    zhuwd  
       125 天前
    @bjfane 这个方案是不是相当于每次路由跳转都要拉一下 version.json 文件?
    ChefIsAwesome
        27
    ChefIsAwesome  
       125 天前
    动态加载 js 文件时会出现这种问题。最常见的就是做 spa ,并且每个路由的 js 是动态加载的。因为 { /path: xx.js } 这个是写在最初访问网页时下载的 js 里的。而 spa 切换页面时不会重新下载 html ,也就不会重新下载最初的 js 。
    实际上这个问题等同于后端接口升级了,用旧版本客户端的人要怎么办。
    原生应用一般就是保留旧版本的资源,再加一个检查版本,提示升级的功能。
    网页跟原生应用不一样,不存在死守着旧版本不放的情况。保留一个旧版本就行了。
    sugars
        28
    sugars  
       125 天前
    @anguiao 他的意思是不刷新页面啊,你这个不还得去刷新页面才能重新访问 index.html
    anguiao
        29
    anguiao  
       125 天前
    @sugars 确实,欠考虑了。
    lower
        30
    lower  
       125 天前
    @kongkongye 层主不是说了,在 error 的时候处理么,都 error 了,随便提示个网络连接异常啥的把用户哄过去……
    DOLLOR
        31
    DOLLOR  
       125 天前
    (await fetch(`./index.html?nocache=${Date.now()}`)).headers.get('last-modified')
    cloverstd
        32
    cloverstd  
       125 天前
    你的问题是发布后,老的页面的 js 没法访问了,增量发布就行,不要删除老的文件,反正静态资源文件名有 hash
    lerry
        33
    lerry  
       125 天前
    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  
       125 天前
    下班的时候更新呗,又不愿意用 websocket 。
    ~~js 名字匹配重定向,曲线救国~~
    wanguorui123
        35
    wanguorui123  
       125 天前
    缓存设置短点 1 小时过期,开启 302 ETag 检查
    bjfane
        36
    bjfane  
       125 天前
    @zhuwd 是的,一个静态文件,但是内容很短
    kongkongye
        37
    kongkongye  
    OP
       125 天前 via iPhone
    @lerry 我最后思考出的解决方案几乎跟你这一致
    lizy0329
        38
    lizy0329  
       122 天前
    你傻啊,发布代码为什么要将之前的文件删掉?要做到非覆盖式发布,而不是覆盖式发布
    a570295535
        39
    a570295535  
       120 天前
    你可以在页面上写个 js 判断调用的 js 是否加载成功,成功就忽略,没成功就提醒用户,现在网页升级了,你是否刷新一下,不刷新就给老子滚!
    a570295535
        40
    a570295535  
       120 天前
    把这句加到其他 js 的前面:
    <script type="text/javascript">window.addEventListener('error',function(){document.write("出错了二逼,<a href=\"javascript:location.reload();\">给爷刷新</a>");},true);</script>
    WenJimmy
        41
    WenJimmy  
       119 天前
    和 22 楼一样
    生产构建的时候生成一个 version.json 一并发布到网站目录,在路由守卫和接口请求前检查根目录 json 内容,不一致就提醒更新
    coolzjy
        42
    coolzjy  
       112 天前
    1. 所有资源上传 OSS 保留历史版本
    2. 使用 MPA ,切换页面直接请求新的 html
    3. 不使用 code splitting ,所有页面打成一个包

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

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

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

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