微前端主应用监听子应用的axios请求

328 阅读1分钟

需求背景

  1. 登录后做权限控制,没有权限的用户跳转到无权限页面
  2. 外网访问做了菜单级别权限控制,有的菜单在外网是不能访问的,需要展示无权限页面

需求分析

针对这两个需求,要做到以下两点:

  1. 写一个静态页面给后端,登录后让后端跳到这个静态页面的路由,
  2. 对于菜单级别控制,只能去替换内容区展示,不能影响到页面的地址(所以不能做路由级别控制)

image.png

难题

  1. 接口是子应用的接口返回804,才展示无权限,不是在主应用的接口控制
  2. 由于之前的项目做了tab切换以及页面的keep-alive,所以当页面来回切换时,是不会请求接口的。

解决方案

  1. 针对难点1,我考虑是封装一层xhr监听,只要在当前浏览器下展示的页面(不管是主应用还是子应用),所有的ajax请求,都是通过一个xhr的原型对象实例化而来的,所以只要在xhr层进行封装,就完美解决了父子应用不是一个axios的问题。
(function () {
  const XHR = XMLHttpRequest.prototype;
  const send = XHR.send;
  XHR.send = function () {
    this.addEventListener('load', function () {
      const response = JSON.parse(this.response)
      console.log('response', response);
      if (response.code == 804) {
        return store.commit('login/ADD_NOT_PERMISSION_TAB')
      }
    })
    return send.apply(this, arguments)
  }
})();
  1. 针对tab切换不发送请求的情况,我是在xhr封装的前提下,如果当前子应用页面有804返回,就记录在store中,然后在页面级别写一个computed来进行监听$route
    // store
    ADD_NOT_PERMISSION_TAB(state) {
        // 找到当前的tab的Code
        const { activeMenuTab } = state;
        // 从tabs列表中找到当前tab的对象
        const currentTab = state.menuTabs.find(tab => tab.code === activeMenuTab)
        if (currentTab) {
            // 存入当前tab的path地址
            state.notPermissionTabs.push(currentTab.path.split('?')[0])
        }
    }
 //main.vue
    <template>
        <not-permission v-show="notPermission"></not-permission>
          <!-- micro 子应用页面 -->
          <div style="width:100%;height:100%" v-show="!notPermission && mainContainer === 'micro'">
            <el-container class="content-wrap" data-id="subapp-viewport" v-for="item in microApps" :key="item.name"
              :id="item.name" v-show="$route.path === item.routePath">
            </el-container>
          </div>

    </template>
    <script>
        computed: {
            ...mapGetters(['notPermissionTabs']),
            notPermission() {
                const { fullPath } = this.$route
                return this.notPermissionTabs.find(path => path === fullPath.split('?')[0])
              },
        }
    </script>