目前碰到的情况是前端重新构建部署后,js 之类文件名都变了,前端点击另一个页面就白屏(控制台报错 js 文件找不到),而很多用户比较小白就会反馈页面出问题了而不是刷新页面。
所以想着重新部署后应该通知到用户应该刷新前端页面,目前能想到的方式是所有请求都自动加上前端当前版本,通过工具重新构建后通知后端修改前端最新版本号,然后前端页面请求时就能返回信息让前端提示页面需要刷新,不知有没更好的办法?
1
kongkongye OP 不知道大厂都是怎么解决这个问题的,像我们企业内部系统,可能一天发布几次前端更新,就很容易碰到这种情况。
|
2
ksc010 2022-05-26 19:11:31 +08:00
简单的方法就是 捕获异常 然后弹窗提示需要刷新重拾下
|
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 参考一下吧 |
4
westoy 2022-05-26 19:13:20 +08:00
我之前一个简单的类 CRM 是直接维护一个 websocket, 下发各种刷新 settings 、语言包的命令, 不过用的人少, 一般也就在线个几十个.......
你可以考虑 window.onerror 捕捉错误, 看情况 fetch 一个最新版本, 版本落后就强制 reload |
5
kongkongye OP @ksc010 我的意思就是这个,就是现实很少碰到过这种情况,想着一般都是一个网页用完就关,出问题就刷新,都不知大厂在这个问题上有没考虑过,不好参照
|
6
dcsuibian 2022-05-26 19:14:37 +08:00 via Android
更新版本的时候,把之前的 js 都删掉了?
|
7
emonc 2022-05-26 19:14:56 +08:00
🤔用路由守卫怎么样?
|
8
kongkongye OP @westoy 不喜欢 ws ,感觉不稳定容易断,还占服务器资源
|
9
kongkongye OP @westoy 也不喜欢强制 reload ,没提示话用户会觉得莫名奇妙页面刷新了
|
10
kongkongye OP @westoy 或者比如用户在填表单,你给强制 reload 了。。。
|
11
ksc010 2022-05-26 19:19:48 +08:00
@kongkongye 这个方法 我感觉是最简单 前端加几行代码就搞定了
监听全局异常错误,然后也可以再判断下异常类型啥的,就因为很少遇到,我感觉稍微弄下就行 |
12
estk 2022-05-26 19:19:50 +08:00
旧的 js 我都一直保留,这样哪怕用户缓存了,至少还能访问旧版
|
13
kongkongye OP @estk 清了节省空间,看着清净,毕竟不是访问量很大的项目,没考虑这
|
14
hmm1225 2022-05-26 19:58:36 +08:00
你 html 文件不缓存不就可以了
|
15
makelove 2022-05-26 21:45:33 +08:00
打包时生成版本号至应用 js ,应用里写个定时每隔 1 分钟调用后端接口发现当前版本不是最新就提示刷新
|
16
wenzichel 2022-05-26 22:23:06 +08:00
刚看描述不明白为什么会出现白屏,原来是把旧的静态资源删除了,这不应该啊。你的静态资源应该增量更新啊,每次发布的静态资源都带有 hash ,发布到 CDN 上。
如果实在是想节省空间,那就单独跑脚本,比如每隔一星期定期进行清理,相同名字的静态资源,只保留最近 30 天的,若只剩下 1 个,就不再删除。 但我还是建议您把静态资源发布到 CDN 上! |
17
wenzichel 2022-05-26 22:26:00 +08:00
所以你的方案不应该放在如何让用户强制刷新页面,而是如何进行增量更新。
若 html 没有过期,依然访问的是旧资源,等 html 过期了,自然访问的就是新资源了。 |
18
bojackhorseman 2022-05-26 22:55:01 +08:00 via iPhone
@wenzichel 我目前也遇到这个问题,以前部署是直接把文件通过 sftp 上传上去的,现在每次部署都是打包后的产物打一个镜像推到 docker 仓库里,这样就没法增量更新了吧。
|
19
Vegetable 2022-05-26 23:04:30 +08:00
1. 不要立刻清除旧的资源
2. 提示用户有更新,请刷新页面 其实就是把网页当作客户端对待嘛,至于实现更新提醒,方法挺多的。随便说一个不一定行得通,本地记录页面初始化的时间,前端 1 分钟 head 一次 index.html ,判断 Last-Modified |
20
arischow 2022-05-26 23:05:09 +08:00
静态资源不随着新版本发布而删除
|
21
gouflv 2022-05-27 00:24:03 +08:00 via iPhone
典型的 没找到原因就开始想解决方案
|
22
bjfane 2022-05-27 02:18:49 +08:00
哈哈哈,好巧,这是我面试题库里的题之一,我的方案是路由守卫里加实现,做法也很简单,/version.json 是发布时候的一个时间戳 - {202205234345564},beforeRoute 里有动作就请求 /version.json?{random},和当前程序里的 version 不一致就提示 并自动刷新
ws 和轮训都不太行,开销太大。 |
23
Puteulanus 2022-05-27 02:36:32 +08:00
我们是用的 ws ,脚本是在 nginx 里用 replace 直接注入到页面 html 里的,所以只有测试环境有,打开页面的时候会建一个到通知服务的连接,然后 pipeline 上一旦重新部署了会调一下通知服务,对所有当前连接用户广播一个通知过去
那种页面挂后边挺长时间甚至出门吃了个饭 ws 已经断了太久的,就给个提示说网页可能不是最新了 当时的需求是 QA 说可能测试环境布了新版本他们不知道,测出来的还是老版本前端的 bug ,特别是有了零停机部署之后,部署过程中服务是完全不中断的,所以做了个通知给当前正在使用网页的人 |
24
aaronlam 2022-05-27 06:11:43 +08:00 via iPhone
|
25
anguiao 2022-05-27 07:52:28 +08:00
你这个需求的话,不缓存 HTML (或者协商缓存),只缓存静态文件,不就行了么。
静态文件的文件名都是带 hash 的,只要 HTML 更新了,这些静态文件也会跟着更新。 我是用 nginx 的 request_filename 来做的,目前用下来没发现有什么问题。 |
27
ChefIsAwesome 2022-05-27 08:37:16 +08:00 1
动态加载 js 文件时会出现这种问题。最常见的就是做 spa ,并且每个路由的 js 是动态加载的。因为 { /path: xx.js } 这个是写在最初访问网页时下载的 js 里的。而 spa 切换页面时不会重新下载 html ,也就不会重新下载最初的 js 。
实际上这个问题等同于后端接口升级了,用旧版本客户端的人要怎么办。 原生应用一般就是保留旧版本的资源,再加一个检查版本,提示升级的功能。 网页跟原生应用不一样,不存在死守着旧版本不放的情况。保留一个旧版本就行了。 |
30
lower 2022-05-27 09:26:40 +08:00
@kongkongye 层主不是说了,在 error 的时候处理么,都 error 了,随便提示个网络连接异常啥的把用户哄过去……
|
31
DOLLOR 2022-05-27 09:27:00 +08:00
(await fetch(`./index.html?nocache=${Date.now()}`)).headers.get('last-modified')
|
32
cloverstd 2022-05-27 09:35:36 +08:00
你的问题是发布后,老的页面的 js 没法访问了,增量发布就行,不要删除老的文件,反正静态资源文件名有 hash
|
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()}`); |
34
hevi 2022-05-27 09:36:29 +08:00
下班的时候更新呗,又不愿意用 websocket 。
~~js 名字匹配重定向,曲线救国~~ |
35
wanguorui123 2022-05-27 10:13:04 +08:00
缓存设置短点 1 小时过期,开启 302 ETag 检查
|
37
kongkongye OP @lerry 我最后思考出的解决方案几乎跟你这一致
|
38
lizy0329 2022-05-30 18:45:32 +08:00
你傻啊,发布代码为什么要将之前的文件删掉?要做到非覆盖式发布,而不是覆盖式发布
|
39
a570295535 2022-06-01 22:02:05 +08:00
你可以在页面上写个 js 判断调用的 js 是否加载成功,成功就忽略,没成功就提醒用户,现在网页升级了,你是否刷新一下,不刷新就给老子滚!
|
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> |
41
WenJimmy 2022-06-02 16:36:41 +08:00
和 22 楼一样
生产构建的时候生成一个 version.json 一并发布到网站目录,在路由守卫和接口请求前检查根目录 json 内容,不一致就提醒更新 |
42
coolzjy 2022-06-09 22:45:01 +08:00
1. 所有资源上传 OSS 保留历史版本
2. 使用 MPA ,切换页面直接请求新的 html 3. 不使用 code splitting ,所有页面打成一个包 加版本、每次检查、提示刷新这套方案不管从技术上还是从用户角度都太不友好了。 |
43
ymcz852 2022-06-15 11:17:28 +08:00
@wenzichel 大佬,不好意思打扰了,想问下按照你这种方案的话,具体是怎么操作呢?每次打包都会生成新的 html 和 js 等静态资源的包,那么 oss 上就会有新的 A 包和旧的 B 包,cdn 那个地址要如何指向新的 A 包里的 html 呢?是要用先访问 Ngnix 的地址,然后指向 cdn 里的新的 A 包里的 html 吗?
|
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 页面了,就可以了。 当然,如果一定在发布后,所有用户都访问最新的资源,那就模仿游戏里的“停机维护”。在发布之前,所有的访问都导向到维护页面,等发布完成后,再把流量导过来。 |
45
ymcz852 2022-06-15 15:34:52 +08:00
@wenzichel `为保证访问的链接不变,html 发布是固定的名字`请问这里是如何操作的,如何通过固定的链接访问到不同的包里的 html 呢?
|
47
GreatAuk 2022-06-28 23:20:16 +08:00
因为前端项目是容器部署,不知道怎么做增量更新,所以自己写了个打包插件 https://github.com/GreatAuk/plugin-web-update-notification ,通知用户刷新页面。楼上用打包时间当版本号的想法也不错,我到时也加下这个功能😁。
|