记录一次老平台改造通知用户刷新页面,纯前端实现

记录一次老平台改造通知用户刷新页面,纯前端实现

方案概述

背景

前端构建完上线,用户还停留还在老页面,用户不知道网页重新部署了,跳转页面的时候有时候js连接hash变了导致报错跳不过去,并且用户体验不到新功能。
客户打网页后,长时间不关闭对应标签页,也不刷新页面(在中后台管理项目挺常见的),且期间服务器页面有更新,经常出现

现状

目前我们或者合作商情况有如下几种情况:

  1. 目前路由hash模式,也就是锚点的形式,造成缓存问题;
  2. 在用户无感知的情况下升级平台,而用户因历史访问,无法获取最新的资源,造成用户体验差;
  3. 升级平台后,可能出现资源访问不到情况;

在现有的平台体系中,由于现在平台架构趋于一个成熟的阶段,基于改动最小、影响最小的原则的情况下,来设计适合目前平台的一套合理的方案解决这些问题;

问题本质

目前平台采用的hash的模式处理,也就是我们常说的锚点的形式,改方式的和history的不同是,histroy 的每次url变化都会像后端服务器请求,会重载页面index.html,这就是单页面history 需要在服务器上配置重定向到index.html的原因;而我们平台使用hash的形式,这种形式,只有在首次加载或者刷新页面的时候会重新请求服务器的index.html,相应的资源在这种情况下才会加载新的资源,url 地址变换并不会向history一样请求服务器,而是前端自主完成,所以在第一次访问完成之后,主要的js已经加载啦,后面操作都是根据主js的相关解析,请求相应的资源!所以在这种情况更新系统 造成资源是旧的或者资源请求不到的情况!

方案设计

前提

基于目前的平台框架,一切改动不能脱离现有的框架,对现有的入侵最小,其他的项目直接复用。

设计

  1. 打包生成的目录生成相应的项目指纹信息,也就是表示,可以是版本号、时间戳、哈希值等等;

  2. 路由钩子触发检测当前版本或者资源是否最新状态,来处理相应的逻辑,流程图如下

    tips:上面流程有点改动,改成点击菜单触发,这个在生产环境上大量测试上的改动。

实现

  1. 编写rollup(vite)插件

  2. vite打包改造,下面可以根据项目需要是否考虑加入,viite本身的打包模式,文件发生变动,打出来的文件名hash 会发生变化,未改动的文件还是之前的文件名格式

    tips: 上面为了好看,当然也可以不改,默认输出的就是带hash的js文件;

  3. 路由钩子处理 菜单上点击菜单处理

tips: 为啥没有放到钩子里面处理,是因为点击菜单会有请求资源直接报错啦,不会走钩子,所以无法触发更新的接口,当然可以放到离开的钩子上处理,目前用的保守做法,点击前置触发。

  1. 服务器Nginx上配置,红色部分是为了重载index.html禁止缓存这个html信息

通过 nginx ,禁用缓存:

bash 复制代码
# nginx.conf
location / {
  root html;root /Volumes/wanglaibin/work/vite-project/dist
  index index.html index.htm;

  if ( $uri = '/index.html' ) { # disabled index.html cache
    add_header Cache-Control "no-cache, no-store, must-revalidate";
  }

  try_files $uri $uri/ /index.html;
}

直接通过 html meta 标签禁用缓存:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>

  <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
  <meta http-equiv="Pragma" content="no-cache" />
  <meta http-equiv="Expires" content="0" />

</head>
</html>

其他补充

浏览器放大缩小,tab页激活触发

javascript 复制代码
	document.addEventListener('visibilitychange', async () => {
		if (document.visibilityState === 'visible') {
			console.log('当前会话被激活')
			await versionCheck()
			console.log('当前会话被激活-end')
		}
	})

浏览器聚焦触发

javascript 复制代码
  window.addEventListener('focus', async() => {
		console.log('当前会话成为焦点')
		await versionCheck()
		console.log('当前会话成为焦点-end')
  })

浏览器js资源加载失败

javascript 复制代码
	window.addEventListener('error', async (err) => {
		const errTagName = (err?.target as any)?.tagName
		if (errTagName === 'SCRIPT'){
			console.log('js 资源加载失败')
			await versionCheck()
			console.log('js 资源加载失败-end')
		}
	},
	true)

写在最后的话

其实具体到项目场景更为复杂,所以我们都是从问题入手、排查、方案等处理方式,不同的项目不同的处理方式,当然目前的对于当前来说更好的!当然可能过几个月就不一定啦!

抛出一个问题

其他我们平台还有比较棘手,目前已经处理,在测试过程中。我可以跟你们描述下问题就是可以一个浏览器多个tab可以登陆不同的账号,也可以登陆相同的账号,不同的账号不同的token,相同的账号也是不同的token 但是这些token写到session里面,页面内部也可以新开tab,内部新开的tab是相同的token,系统也要有一个token续期的功能,系统内部新开的tab 保证token同步不能失效,系统内部两个token ,一个接口token,一个刷新token,要用刷新token在失效前换取新的token之后同步到系统内部新开的tab中,但是但不能影响其他的账号登陆以及相同账号登陆的token。
或许为啥这样设计,没办法历史原因,现在就是后端不动,前端做token续期。

相关推荐
@大迁世界3 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路12 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug15 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213817 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中39 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路42 分钟前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端