需求
当token过期的时候,刷新token,前端需要做到无感刷新token,即刷token时要做到用户无感知,避免频繁登录,当同时发起两个或者两个以上的请求时,防止多次刷新token,其他接口获取到新的token后继续执行请求操作。
问题解决
当第二个过期的请求进来,token正在刷新,我们先将这个请求存到一个数组队列中,想办法让这个请求处于等待中,一直等到刷新token后再逐个重试清空请求队列。
那么如何做到让这个请求处于等待中呢?为了解决这个问题,我们得借助Promise。将请求存进队列中后,同时返回一个Promise,让这个Promise一直处于Pending状态(即不调用resolve),此时这个请求就会一直等啊等,只要我们不执行resolve,这个请求就会一直在等待。当刷新请求的接口返回来后,我们再调用resolve,逐个重试。最终代码:
let isRefreshing = false// 是否正在刷新的标记
let requests = []//重试队列
let ajaxtimes = 0;//同时发送异步代码次数
function cloudRrequest(paramsList) {
let _this = this;
let params = JSON.parse(JSON.stringify(paramsList))
ajaxtimes++;
params.url =xxx+ params.url,//这里自己封装接口
if (!params.data) {
//参数
params.data = {
}
}
if (!params.header) {
//请求头
params.header = {
}
}
if (params.data.token) {
//是否传入了token
console.log("token~~~~~");
} else if (getTokenSync) {
//缓存token存在则赋值
params.data.token = getTokenSync
}
return new Promise((resolve, reject) => {
wx.request({
...params,
method: params.method || "GET",
success: function(res) {
if (res.statusCode == 200) {
//http状态码是否成功
var data = res.data;
if (data.code != 200) {
//后端返回的状态码是否成功
if (data.code == 403) {
//当token过期执行
//这里是重点:让这个Promise一直处于Pending状态(即不调用resolve)
new Promise(resolve2 => {
// 用函数形式将 resolve 存入,等待刷新后再执行
requests.push(token => {
// params.headers.Authorization = `${token}`
if (!paramsList.data) {
paramsList.data = {
}
}
paramsList.data.token = `${
token}`
//这里resolve
resolve(_this.cloudRrequest(paramsList, messages))
})
})
if (!isRefreshing) {
//成功状态
console.log("token过期");
isRefreshing = true//第一个请求后,后面请求都不进入执行请求
//调用刷新token的接口
return _this.cloudRrequest({
url: 'refreshToken',
data: {
refreshToken: wx.getStorageSync('refreshToken') },
method: 'POST'
}).then((data) => {
console.log(data);
if (data.token) {
wx.setStorageSync('token', data.token);
// response.headers.Authorization = `${token}`
// token 刷新后将数组的方法重新执行
requests.forEach((cb) => cb(data.token))
requests = [] // 重新请求完清空
return
}
}).catch(err => {
//获取token失败,删除旧token,跳到登录页
try {
wx.removeStorageSync('token')
} catch (error) {
}
wx.reLaunch({
url: '/pages/login/login'
})
return Promise.reject(err)
})
}
} else {
//其他错误
wx.showModal({
title: '提示',
content: data.message,
});
}
} else {
//请求成功时直接返回数据
resolve(data.data);
}
} else {
//其他错误
wx.showModal({
title: '提示',
content: res.data.message,
});
}
},
fail: function(err) {
console.log();
reject(err)
},
complete: function() {
ajaxtimes--
//当执行请求最后一个请求后关闭加载动画
if (ajaxtimes === 0) {
wx.hideNavigationBarLoading()//在当前页面隐藏导航条加载动画
wx.stopPullDownRefresh() //停止当前页面下拉刷新。
}
},
})
})
}
module.exports = {
cloudRrequest: cloudRrequest,
}
这里参考了
https://juejin.cn/post/6983582201690456071#heading-4
使用axios实现无感刷新的案例