本文章主要记录个人在项目开发过程中遇到的多个请求同时发起,失败的请求重试的问题。参照网上许多token无痛刷新案例,根据自己项目做了一些补充。需要明白的是在异步请求的情况下,多个请求同时发起,如果token无效,则必然这几个请求都需要重试,当我们收到第一个401响应(表示token过期)就拿刷新token去刷新,然后重试请求,如果token更新前所有的401响应都已经放在了队列中,可以直接参考该文章:前端axios无痛刷新token,还有一种情况是在我们成功刷新了token过后部分token刷新前响应才响应回来,这就需要我们多做一次判断:
//非首次收到401响应的请求
const reqToken = config.headers.Authorization//该请求发起时携带的token
const token =getToken()
//token已经更新就重试请求
if (reqToken !== token) {
config.headers['Authorization'] = token
return service(config)
} else {
//token未更新则放在队列中,更新后再释放
return new Promise((resolve) => {
requests.push((rToken) => {
config.headers['Authorization'] =rToken
resolve(service(config))
})
})
}
完整代码如下:
service.interceptors.response.use(
response => {
const { status } = response.data
//当后端返回状态码为401,代表token过期:token过期首先通过刷新token进行刷新,如果刷新成功则失败请求重试,如果刷新失败就重新登录
if (status === 401) {
const config = response.config
if (!isRefreshing) {
isRefreshing = true;
return reToken(getReToken()).then((res) => {
const { accessToken, refreshToken } = res.data
//更新浏览器token和retoken
setToken(accessToken)
setReToken(refreshToken)
//当前请求重新设置token
config.headers['Authorization'] = accessToken
//token刷新前的401请求队列重试
if (requests.length > 0) {
requests.forEach(cb => cb(accessToken))
requests = []
}
return service(config)
}).catch((error) => {
requests = []
//token刷新失败,只能去登录
}).finally(() => {
isRefreshing = false
})
} else {
//非首次收到401响应的请求
const reqToken = config.headers.Authorization//该请求发起时携带的token
const token = getToken()
//token已经更新就重试请求
if (reqToken !== token) {
config.headers['Authorization'] = token
return service(config)
} else {
//token未更新则放在队列中,更新后再释放
return new Promise((resolve) => {
requests.push((rToken) => {
config.headers['Authorization'] = rToken
resolve(service(config))
})
})
}
}
}
return response.data
},
error => {
Message({
message: error.message,
type: 'error'
})
return Promise.reject(error)
}
)