内部权限平台迁移,前端如何做优雅降级?

背景:原本的权限系统太老了,而且问题很多,有些流程设计也不合理。部门需要把所有项目都迁入新开发的权限系统。但在使用的前2个月内,需要做兜底方案,防止新权限系统挂壁后,其他接入的平台也无法正常使用。

为了方便讲,下面将

  • 旧权限系统统称 old-s
  • 新权限系统统称 new-s

兜底方案/优雅降级 是什么意思?

  • 当新权限系统new-s 出bug了,不能正常返回时,其他接入的new-s的平台应该回退到old-s去。保证平台能用(目前前端平台有10+)

问题分析:

  1. 前端不用动,就让后端适配好,行不行?
  2. 如何知道new-s出问题了?
  3. 前端知道出问题后,如何回退?
  4. new-s的问题修复完了,该如何优雅的切换回new-s?

1. 前端不用动,就让后端适配好,行不行?

不行

为什么前端也要回退?

  • 原本只需后端做识别,返回正确的接口就行了,前端不用动的。
  • 但是由于新的权限系统new-s的设计和old-s不一样(old-s和平台更加耦合),这样导致,如果要退回old-s,前端的代码也必须回退到old-s的版本去,否则用接new-s的版本去调old-s的接口,可能造成平台部分功能有问题

2. 如何知道new-s出问题了?

首先简单讲一下正常的流程

  1. 某用户xiaoming输入账号,密码和token,进入前端平台A
  2. 然后到了A的首页, 开始调接口去获取资源(请求头会带上xiaoming个人的token,他有什么权限就返回对应的资源,没权限的话,会提示去申请)
  3. 如果此时new-s挂了,接口都会返回不了,那么平台A将陷入瘫痪
  4. (注:所有的接口都要先通过权限系统校验)

由上面的流程,我们可以知道,平台和new-s交互的过程是调接口。如果我们想知道new-s是否有问题,那么肯定是在调接口的过程中,去判断

接口挂了后,就没有返回值了,所以,new-s的正常与否的结果,最好是放在响应头

最终:

  • 让所有的接口在响应头加2个字段。后端去判断:正常返回 new-s,new-s异常则返回 old-s
    1. Access-Control-Expose-Headers: current-system // 这个字段不加的话,前端无法在响应头获取current-system字段
    2. current-system: new-s // 正常返回 new-s
    3. current-system: old-s // new-s异常,则返回 old-s

3. 前端知道出问题后,如何回退?

首先,不能重新发布(用old-s的分支重新发布解决问题,太low了,而且发布也要时间,切回new-s又要重新发布)

前端的解决思路:

  1. 把old-s打包npm run build,然后给dist包改名成old,
  2. 把new-s打包npm run build,生成dist
  3. 然后把整个old包,剪切到 new-s的dist包里面去。
  4. 目录结构如下
    dist.png

具体代码实现

  1. 代码内判断当前环境是new-s还是old-s
  2. 配置webpack.config.js(当前是old-s分支)
  3. (当前是old-s分支)先build,在切new-s分支,在只合old文件

1. 代码内判断当前环境是new-s还是old-s

在 new-s分支 和 old-s分支 都要加入以下判断代码!!

找到src/axios/index.js (配置axios的响应拦截器)

  1. // 在 new-s分支 和 old-s分支 都要加入以下判断代码!!
  2. // 添加响应拦截器
  3. instance.interceptors.response.use(function (response) {
  4. const isOld = location.pathname.includes('old')
  5. const env = (response.headers.current_system || response.headers['current-system'] || '').toLowerCase()
  6. if (env === 'old-s' && !isOld) {
  7. location.replace('/old')
  8. } else if (env === 'new-s' && isOld) {
  9. location.replace('/')
  10. }
  11. // 增加上面的,下面的不变 ...
  12. })

2. 配置webpack.config.js(当前是old-s分支)

配置打包的出口为old

  1. const ROOT_PATH = path.resolve(__dirname)
  2. const distDir = 'old' // 此处 从dist 改成 old
  3. const DIST_PATH = path.resolve(ROOT_PATH, distDir)
  4. output: {
  5. path: DIST_PATH,
  6. publicPath: PUBLIC_PATH,
  7. ...
  8. },

3. (当前是old-s分支)先build,在切new-s分支,在只合old文件

  1. (当前是old-s分支)npm run build 得到old文件夹,然后git push
  2. 切分支到new-s分支(此时根目录无old文件夹)
  3. 注意此时在new-s分支:执行 git checkout old-s old
    • 参数old-s是分支old-s,如果你的old-s分支叫release-old,那此参数就是release-old
    • 参数old就是old文件夹
  1. 此时根目录应该有old文件夹
    此时有2条路:
    1. 情况1:当前的new-s分支已经打包完成
      • 那么你需要手动把old文件夹拖入dist包内
  1. 情况2:当前的new-s分支还没打包 (线上打包必须走这一步)
    • 那么你可以配置一下webpack.config.js在build,以后都不用手动copy了,可以利用webpack帮你复制
  1. const CopyWebpack = require('copy-webpack-plugin') // 没安装的自行安装一下:npm i -D copy-webpack-plugin
  2. // 在production的配置中,增加plugin
  3. if (env.NODE_ENV === 'production') {
  4. ...
  5. baseConfig.plugins = (baseConfig.plugins || []).concat([
  6. ...
  7. new CopyWebpack(
  8. [{
  9. from: './pmc',
  10. to: 'pmc'
  11. }]
  12. )
  13. ])
  14. ...
  15. }
  1. 然后用dev分支,merge new-s分支,就可以发布了

4. new-s的问题修复完了,该如何优雅的切换回new-s?

参考上面的代码。已经完成了切回功能:

  • 需要在old-s分支 也 加上响应拦截的那段代码,就能优雅的切回了

码字不易,点点小赞鼓励~