插件事件机制
前面的章节中,已经说了如何注册和使用预设,这里是最后一步说明。在defHttp.use(basePlugin);
之后,你需要注册两个axiosError401
和axiosGetToken
事件
这么做的原因有二,第一,我们在二次封装请求的时候,一般接口访问,都是需要带token的。第二在请求401登出时候业务项目需要被动登出。
为什么要用on?
因为@aplus-frontend/aplus-axios-vue-preset
和@aplus-frontend/aplus-axios-react-preset
这两个预设,内部实现了一个简单的发布订阅类
偏向于传统的做法可能像下面这样,函数依赖注入目前这种做法已经被放弃
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
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
接口,也同时初始化store
,store
依赖了getUserInfo
,getUserInfo
依赖了defHttp
,defHttp
依赖了store
中的getToken
或者logout
(有些项目,会把获取用户信息或者页面登出逻辑写在store中),就会形成循环依赖,会导致项目跑不起来了😂

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

例如你可以
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 ,事件只能是axiosError401 和axiosGetToken | 是 |
off | 注销生命周期 | (eventHandlers: Array<{[key in EventType]?: EventHandler;}>)=>void ,事件只能是axiosError401 和axiosGetToken | 否 |
emit | 触发生命周期 | (event: EventType, ...args: any[]) ,事件只能是axiosError401 和axiosGetToken | 否 |