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

457 阅读5分钟

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

背景:原本的权限系统太老了,而且问题很多,有些流程设计也不合理。部门需要把所有项目都迁入新开发的权限系统。但在使用的前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出问题了?

首先简单讲一下请求接口的流程

某用户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又要重新发布)

前端不用发布的解决思路:

  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的响应拦截器)

// 在 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文件

  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文件夹
  4. 此时根目录应该有old文件夹

    此时有2条路:

    1. 情况1:当前的new-s分支已经打包完成

      • 那么你需要手动把old文件夹拖入dist包内
    2. 情况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'
                  }]
              )
          ])
          ...
      }
      
  5. 然后用dev分支,merge new-s分支,就可以发布了

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

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

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

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