前置知识(axios
,proveAxios的基本使用),先看看最终效果是如何
import { initializationAxios, InitializeContainer, instanceAlias, interceptorsResponseSuccess, Module } from '@zealforchange/proveaxios'
import { UserAuthorization, useUserAuthorizationHelper } from '@zealforchange/proveaxios/userAuthorization'
import { AxiosResponse } from 'axios'
// useUserAuthorizationHelper 用于 配置 token续传插件(UserAuthorization) 配置
useUserAuthorizationHelper({
authorizationRequired: true, // 是否验证token已过期
statusExpirationCode: 401, // 如果同意验证token过期,判断返回的code是否等于401,为true则立即触发 refreshToken 函数
refreshToken: async () => {
// 业务逻辑
const result = await helper({ url: '/refreshToken' })
// ... 省略无关代码
},
// 当 refreshToken 调用结束,会重试此前由token过期导致请求失败的请求
})
@Module([UserAuthorization]) // 重点为 UserAuthorization 插件再此配置token续传插件
@initializationAxios({
baseURL: '<http://localhost:3000/user>',
})
class UserAuth {
@interceptorsResponseSuccess()
static response(res: AxiosResponse) {
return Promise.resolve(res.data)
}
}
const g = new InitializeContainer().collect([UserAuth]) //初始化UserAuth生成实例化axios
const helper = g.get(instanceAlias.firstInstance) // 取出由UserAuth实例化的axios
it('verify', async () => {
// 这是一个token已过期的请求
// 调用链路:第一次调用此请求会进入 refreshToken 回调,刷新token后会重新调用此请求
// resultList 不会是token过期的响应,而是有正常token getList请求的响应
const resultList = await helper({ url: '/getList' })
expect(resultList).toStrictEqual({ code: 200, data: [1, 2] })
})
如果你没读过书接上文 这一篇文章,你很有可能会认为现有代码非常的冗余,其实不然
接上来我会从0到1的实现 UserAuthorization
插件应该如何实现
首先我想应该先明确,这个插件都需要哪些配置项?
interface userAuthorizationConf<S = unknown> {
authorizationRequired?: boolean // 是否需要授权token
statusExpirationCode?: number // 状态过期码
refreshToken?: ((response: AxiosResponse<S>) => void | Promise<void>) | null // 刷新token handler
}
接下来需要实现proveAxios
特定的插件配置
// userAuthorizationConf 默认配置
const h: userAuthorizationConf = {
statusExpirationCode: 401,
refreshToken: null,
authorizationRequired: false,
}
// 插件优先级,用处是填入 Module 装饰器时将插件所有装饰器的执行顺序进行排序
// TOP 最高优先级
@dynamicModule({ priority: priority.TOP })
export class UserAuthorization {
// 响应成功拦截器
@interceptorsResponseSuccess()
static async res(resp: AxiosResponse) {
// 执行 refreshToken 函数 刷新token
await h.refreshToken?.(resp)
// 刷新token后重试之前因token过期而请求失败的请求
const latestAuthorizationResult = await axios(resp.config)
// 将token刷新后请求成功的结果返回
return Promise.resolve(latestAuthorizationResult)
}
// 通过该函数返回值判断是否需要执行该插件中的响应成功拦截器
@dynamicModuleSuccessInstall(decisionInstaller.installResSuc)
static installSuc(res: AxiosResponse<{ code: number }>) {
// 是否需要判断授权token
if (!h.authorizationRequired) return false
// 当前响应返回的code是否等于 配置中的 statusExpirationCode 字段
// 如果等于则会执行该插件中的响应成功拦截器
if (res.data.code === h.statusExpirationCode) {
return true
}
// 不执行响应拦截器
return false
}
}
// 修改UserAuthorization配置
export function useUserAuthorizationHelper<S>(conf: userAuthorizationConf) {
h.statusExpirationCode = conf.statusExpirationCode
h.refreshToken = conf.refreshToken || null
h.authorizationRequired = conf.authorizationRequired
}
git clone https://github.com.cnpmjs.org/erqiu-sj/proveAxios.git