响应拦截器拦截状态码401刷新token
// 是否正在刷新的标记
let isRefreshing = false;
// 重试队列,每一项将是一个待执行的函数形式
let requestsList = [];
service.interceptors.response.use(
response => {
return response.data;
}, err
);
const err = (error) => {
if (error.response) {
let data = error.response.data
const token = Vue.ls.get(ACCESS_TOKEN)
switch (error.response.status) {
case 401:
if (error.response.data.code == 401 && error.response.config.url !== "/sys/logout") {
var config = error.config; //获取401失败请求的axios中的config配置数据
// 拿到刷新token
const refreshtoken = Vue.ls.get(ACCESS_TOKEN_REFRESH);
// 判断 没有刷新token的处理代码
if (!refreshtoken) {
// 清除过期token
// 跳转到login
Vue.prototype.$Jnotification.error({ message: '系统提示', description: '很抱歉,登录已过期,请重新登录', duration: 4 })
store.dispatch("Logout").then(() => {
setTimeout(() => {
window.location.reload();
}, 1500);
});
return;
}
// 有刷新token
// 要try catch 因为刷新token一般14天过期 有可能还会获取不到refresh_token
if (!isRefreshing) {
isRefreshing = true;
let data = {
refreshToken: Vue.ls.get(ACCESS_TOKEN_REFRESH),
loginFrom: 1,
username: Vue.ls.get(USER_NAME),
};
refreshTokenToToken(
data
).then(res => {
if (res.code == 200) {
var token = res.result.token;
Vue.ls.set(ACCESS_TOKEN, res.result.token, 7 * 24 * 60 * 60 * 1000);
Vue.ls.set(ACCESS_TOKEN_REFRESH, res.result.refreshToken, 7 * 24 * 60 * 60 * 1000);
config.headers['X-Access-Token'] = token;
// 已经刷新了token,将所有队列中的请求进行重试
requestsList.forEach(cb => cb(token));
// 重试完了别忘了清空这个队列
requestsList = [];
return service.request(error.config)
} else {
Vue.prototype.$Jnotification.error({ message: '系统提示', description: '很抱歉,登录已过期,请重新登录', duration: 4 })
store.dispatch("Logout");
window.location.reload();
}
})
.catch(error => {
Vue.prototype.$Jnotification.error({ message: '系统提示', description: '很抱歉,登录已过期,请重新登录', duration: 4 })
store.dispatch("Logout");
window.location.reload();
})
.finally(() => {
isRefreshing = false;
});
} else {
// 正在刷新token,将返回一个未执行resolve的promise
// 保存函数 等待执行
// 吧请求都保存起来 等刷新完成后再一个一个调用
return new Promise((resolve) => {
// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
requestsList.push((token) => {
config.headers['X-Access-Token'] = token
resolve(service(config))
})
})
}
}
break
default:
Vue.prototype.$Jnotification.error({
message: '系统提示',
description: data.message,
duration: 4
})
break
}
} else if (error.message) {
if (error.message.includes('timeout')) {
Vue.prototype.$Jnotification.error({ message: '系统提示', description: '网络超时' })
} else {
Vue.prototype.$Jnotification.error({ message: '系统提示', description: error.message })
}
}
return Promise.reject(error)
};
// 刷新token
function refreshTokenToToken(data) {
return service
.post(
"/sys/refreshToken",
data
)
.then(result => {
return Promise.resolve(result);
});
}