Skip to content

插件事件机制

前面的章节中,已经说了如何注册和使用预设,这里是最后一步说明。在defHttp.use(basePlugin);之后,你需要注册两个axiosError401axiosGetToken事件

这么做的原因有二,第一,我们在二次封装请求的时候,一般接口访问,都是需要带token的。第二在请求401登出时候业务项目需要被动登出。

为什么要用on?

因为@aplus-frontend/aplus-axios-vue-preset@aplus-frontend/aplus-axios-react-preset这两个预设,内部实现了一个简单的发布订阅类

偏向于传统的做法可能像下面这样,函数依赖注入目前这种做法已经被放弃

ts
import { axiosBasePresent } from '@aplus-frontend/axios-base-preset';
//注册插件预设
const basePlugin = axiosBasePresent({
  setToken: (info) => {
    console.log('你的setToken方法', info);
  },
  getToken: () => {
    console.log('你的getToken方法');
  },
  locale: 'zh_CN',
  logout: (b: boolean) => {
    console.log('你的logout方法,httpCode是401时候会被动登出', b);
  }
});

上面的做法也确实没什么问题,也是aplus axios预设最开始的做法。但是在实际项目中问题会复杂很多,比如无论是vue项目或react项目,一般都会在store中有类似的代码

一般中后台项目类似的目录结构如下:

├── package.json
├── src
│   ├── api  //存储项目中业务接口
│   │   │   └── login.ts
│   │   │   └── 其他接口文件.ts
│   ├── assets
│   ├── components
│   ├── utils
│   │   │   └── defHttp.ts //初始化包defHttp实例的地方,提供给项目全局使用
│   ├── hooks
│   ├── router
│   ├── store
│           └── user.ts
│           └── 其他store文件.ts
├── tsconfig.json
└── vite.config.ts
ts
import { getUserInfo } from '@/api/login';

const useUser = create(
  devtools(
    persist<UserState>((set, get) => ({
      info: null,
      token: '',
      merchant: null,
      setUser: (user) => {
        set({ info: user });
      },
      setToken: (token) =>
        set(() => ({
          token: token
        })),
      getToken: () => {
        return get().token;
      },
      fetchUser: async () => {
        const { token } = get();
        if (!token) {
          return Promise.reject(new Error('暂未登录'));
        }
        try {
          const info = await getUserInfo();
          set({ info: info });
          return info;
        } catch {}
      },
      async refreshToken() {
        const { token } = get();
        if (!token) {
          throw new Error('暂未登录');
        }
      },
      clear() {
        set({ token: '', info: null });
      }
    }))
  )
);

注意这个getUserInfo接口,在项目初始化的时候会初始化getUserInfo接口,也同时初始化storestore依赖了getUserInfo,getUserInfo依赖了defHttp,defHttp依赖了store中的getToken或者logout(有些项目,会把获取用户信息或者页面登出逻辑写在store中),就会形成循环依赖,会导致项目跑不起来了😂

发布订阅

为了解决上述的循环依赖问他们,不得不实现一套发布订阅模式,在预设初始化之后,去注册事件,当真正的请求发生时候,读取已注册的事件并执行。打破函数依赖注入模式下,带来的循环依赖问题。

例如你可以

ts
import { axiosEvent } from '@aplus-frontend/axios-base-preset';
axiosEvent.on([
  {
    axiosError401: () => {
      console.log('页面登出逻辑');
    }
  },
  {
    axiosGetToken: () => {
      //发送请求默认全部带token,axiosGetToken注册需要返回项目token方可生效
      return getToken();
    }
  }
]);

上述的axiosEvent.on时机,你可以选择在任何项目代码发生的阶段,可以是在store已经初始化了,也可以是其他任何时机。当需要订阅的内容注册号后,defHttp内部,在正确的生命周期发生时,自动emit。只要保证真正请求发生的时候,可以拿到token,被动登出的时候可以执行401之后的逻辑

axiosEvent方法

属性说明TypeScript 类型是否必须
on注册生命周期(eventHandlers: Array<{[key in EventType]?: EventHandler;}>)=>void,事件只能是axiosError401axiosGetToken
off注销生命周期(eventHandlers: Array<{[key in EventType]?: EventHandler;}>)=>void,事件只能是axiosError401axiosGetToken
emit触发生命周期(event: EventType, ...args: any[]),事件只能是axiosError401axiosGetToken