内部权限平台迁移,前端如何做优雅降级?
背景:原本的权限系统太老了,而且问题很多,有些流程设计也不合理。部门需要把所有项目都迁入新开发的权限系统。但在使用的前2个月内,需要做兜底方案,防止新权限系统挂壁后,其他接入的平台也无法正常使用。
为了方便讲,下面将
- 旧权限系统统称 old-s
- 新权限系统统称 new-s
兜底方案/优雅降级 是什么意思?
- 当新权限系统new-s 出bug了,不能正常返回时,其他接入的new-s的平台应该回退到old-s去。保证平台能用(目前前端平台有10+)
问题分析:
- 前端不用动,就让后端适配好,行不行?
- 如何知道new-s出问题了?
- 前端知道出问题后,如何回退?
- new-s的问题修复完了,该如何优雅的切换回new-s?
1. 前端不用动,就让后端适配好,行不行?
不行
为什么前端也要回退?
- 原本只需后端做识别,返回正确的接口就行了,前端不用动的。
- 但是由于新的权限系统new-s的设计和old-s不一样(old-s和平台更加耦合),这样导致,如果要退回old-s,前端的代码也必须回退到old-s的版本去,否则用接new-s的版本去调old-s的接口,可能造成平台部分功能有问题
2. 如何知道new-s出问题了?
首先简单讲一下正常的流程
某用户xiaoming输入账号,密码和token,进入前端平台A。
然后到了A的首页, 开始调接口去获取资源(请求头会带上xiaoming个人的token,他有什么权限就返回对应的资源,没权限的话,会提示去申请)
如果此时new-s挂了,接口都会返回不了,那么平台A将陷入瘫痪
(注:所有的接口都要先通过权限系统校验)
由上面的流程,我们可以知道,平台和new-s交互的过程是调接口。如果我们想知道new-s是否有问题,那么肯定是在调接口的过程中,去判断
接口挂了后,就没有返回值了,所以,new-s的正常与否的结果,最好是放在响应头内
最终:
- 让所有的接口在响应头加2个字段。后端去判断:正常返回 new-s,new-s异常则返回 old-s
Access-Control-Expose-Headers: current-system // 这个字段不加的话,前端无法在响应头获取current-system字段
current-system: new-s // 正常返回 new-s
current-system: old-s // new-s异常,则返回 old-s
3. 前端知道出问题后,如何回退?
首先,不能重新发布(用old-s的分支重新发布解决问题,太low了,而且发布也要时间,切回new-s又要重新发布)
前端的解决思路:
- 把old-s打包npm run build,然后给dist包改名成old,
- 把new-s打包npm run build,生成dist
- 然后把整个old包,剪切到 new-s的dist包里面去。
- 目录结构如下
具体代码实现
- 代码内判断当前环境是new-s还是old-s
- 配置webpack.config.js(当前是old-s分支)
- (当前是old-s分支)先build,在切new-s分支,在只合old文件
1. 代码内判断当前环境是new-s还是old-s
在 new-s分支 和 old-s分支 都要加入以下判断代码!!
找到src/axios/index.js (配置axios的响应拦截器)
// 在 new-s分支 和 old-s分支 都要加入以下判断代码!!
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
const isOld = location.pathname.includes('old')
const env = (response.headers.current_system || response.headers['current-system'] || '').toLowerCase()
if (env === 'old-s' && !isOld) {
location.replace('/old')
} else if (env === 'new-s' && isOld) {
location.replace('/')
}
// 增加上面的,下面的不变 ...
})
2. 配置webpack.config.js(当前是old-s分支)
配置打包的出口为old
const ROOT_PATH = path.resolve(__dirname)
const distDir = 'old' // 此处 从dist 改成 old
const DIST_PATH = path.resolve(ROOT_PATH, distDir)
output: {
path: DIST_PATH,
publicPath: PUBLIC_PATH,
...
},
3. (当前是old-s分支)先build,在切new-s分支,在只合old文件
- (当前是old-s分支)npm run build 得到old文件夹,然后git push
- 切分支到new-s分支(此时根目录无old文件夹)
- 注意此时在new-s分支:执行 git checkout old-s old
- 参数old-s是分支old-s,如果你的old-s分支叫release-old,那此参数就是release-old
- 参数old就是old文件夹
- 此时根目录应该有old文件夹
此时有2条路:- 情况1:当前的new-s分支已经打包完成
- 那么你需要手动把old文件夹拖入dist包内
- 情况1:当前的new-s分支已经打包完成
- 情况2:当前的new-s分支还没打包 (线上打包必须走这一步)
- 那么你可以配置一下webpack.config.js在build,以后都不用手动copy了,可以利用webpack帮你复制
const CopyWebpack = require('copy-webpack-plugin') // 没安装的自行安装一下:npm i -D copy-webpack-plugin
// 在production的配置中,增加plugin
if (env.NODE_ENV === 'production') {
...
baseConfig.plugins = (baseConfig.plugins || []).concat([
...
new CopyWebpack(
[{
from: './pmc',
to: 'pmc'
}]
)
])
...
}
- 然后用dev分支,merge new-s分支,就可以发布了
4. new-s的问题修复完了,该如何优雅的切换回new-s?
参考上面的代码。已经完成了切回功能:
- 需要在old-s分支 也 加上响应拦截的那段代码,就能优雅的切回了
码字不易,点点小赞鼓励~