alova是一个轻量级的请求策略库,旨在简化接口的管理和使用。你可以通过简单配置参数,即可实现复杂请求如请求共享、分页请求、表单提交、断点续传等,无需编写大量代码,提高开发效率,应用性能,减轻服务端压力。
在请求时我们经常需要通过token授权登录,并在token过期时通过refresh_token刷新token,这边我们来讨论下如何通过alova来无感刷新token,即当发现token过期时自动刷新token,在请求发起处不会感觉到token已刷新。
以下提供了两种思路,每种思路都实现了token在刷新期间让其他请求等待的功能。
在前端判断token过期
这种是在前端判断token是否过期,这通常在登录时有返回token过期时间时使用,思路是在beforeRequest
中判断token是否过期,已过期则先刷新token后继续发送请求,它的优点是不会接收到token过期的响应,因此也不需要重复发送请求。
js
let token = '', refreshToken = '', tokenRefreshing = false, waitingList = [];
const alovaInstance = createAlova({
// ...
beforeRequest: async method => {
if (getCache('token_expire_time') < Date.now() && method.meta?.authType !== 'refreshToken') { // token过期
if (tokenRefreshing) {
// 如果正在刷新token,则等待刷新完成后再发请求
console.log('正在刷新token,等待请求');
await new Promise(resolve => {
waitingList.push(resolve);
});
}
try {
tokenRefreshing = true;
const { refreshToken: newRefreshToken, token: newToken } = await tokenRefresh({ refreshToken });
// 保存新的token和refreshToken
token = newToken;
refreshToken = newRefreshToken;
tokenRefreshing = false;
// 刷新token完成后,通知等待列表中的请求
waitingList.forEach(resolve => resolve());
waitingList = [];
} catch(error) {
// 刷新token失败,可以处理跳转到登录界面等操作
// ...
}
}
method.config.headers.Authorization = token;
},
})
在这里tokenRefresh请求method添加了authType = 'refreshToken'的
meta数据作为标识,才能通过请求。
js
export const tokenRefresh = () => {
const method = alovaInst.Get('/refresh-token', {
localCache: null
});
method.meta = {
authType: 'refreshToken'
};
return method;
}
通过服务端返回的状态判断token过期
这种方式是通过服务端的返回状态判断token是否过期,这通常在登录时没有返回token过期时间时使用,思路是在responded.onSuccess
中通过返回状态判断token是否过期,已过期则刷新token后再次发送请求,它的优点是比较准确,但也会有重复的请求发送。
js
let token = '', refreshToken = '';
let tokenRefreshing = false; // 正在刷新token,让其他请求先等着
let waitingList = [];
const alovaInst = createAlova({
// ...
beforeRequest: async ({ url, config, meta }) => {
console.log(url, '正在请求');
// 如果正在刷新token,则等待刷新完成后再发请求
if (tokenRefreshing && meta?.authType !== 'refreshToken') {
console.log('正在刷新token,等待请求');
await new Promise(resolve => {
waitingList.push(resolve);
});
}
config.headers.Authorization = token;
},
responsed: async (response, method) => {
if (response.status === 401) { // token过期
console.log(method.url, 'token失效,重新获取token');
try {
// 这边防止请求多次刷新token,把在token刷新完成前发送的拦截并等待
if (tokenRefreshing) {
console.log('正在刷新token,等待请求');
await new Promise(resolve => {
waitingList.push(resolve);
});
})
tokenRefreshing = true;
const { token: newToken, refreshToken: newRefreshToken } = await refreshToken({ refreshToken });
token = newToken;
refreshToken = newRefreshToken;
tokenRefreshing = false;
waitingList.forEach(resolve => resolve());
waitingList = [];
console.log('已获得新token并保存', token, `再重新访问${method.url}`);
// 这里因为是重新请求原接口,与上一次请求叠加会导致重复调用transformData,因此需要将transformData置空去除一次调用
const methodTransformData = method.config.transformData;
method.config.transformData = undefined;
const dataResent = await method;
method.config.transformData = methodTransformData;
return dataResent;
} catch(error) {
// 刷新token失败,可以处理跳转到登录界面等操作
// ...
}
}
return response.json();
},
});
至此alova的两种刷新token的思路都实现了,在请求发起处无感知token刷新。
想学习更多 alovajs 的用法,欢迎来alova 官网学习。如果你也喜欢 alovajs,请在Github 仓库中贡献一颗 star,这对我们非常重要。
如果觉得文章对你有帮助,请别吝啬你的赞和评论哈,说说你对 alovajs 怎么看的,或者可以问一些问题,我会尽量回答的,你的支持是我创作的最大动力!哈哈哈哈哈哈~
欢迎加入交流社区
有任何问题,你可以加入以下群聊咨询,也可以在github 仓库中发布 Discussions,如果遇到问题,也请在github 的 issues中提交,我们会在最快的时间解决。
同时也欢迎贡献你的一份力量,请移步贡献指南。