// 计算是否快要过期
const isTokenExpired = () => {
const expireTime = new Date(store.state.accessTokenExpiresIn).getTime()
const timeDifference = expireTime - Date.now()
if (expireTime && timeDifference < 60000) {
return true
}
return false
}
// 是否正在刷新的标记 -- 防止重复发出刷新token接口--节流阀
let isRefreshing = false
// 失效后同时发送请求的容器 -- 缓存接口
let subscribers = []
// 刷新 token 后, 将缓存的接口重新请求一次
function onAccessTokenFetched(newToken) {
subscribers.forEach((callback) => {
callback(newToken)
})
// 清空缓存接口
subscribers = []
}
// 添加缓存接口
function addSubscriber(callback) {
subscribers.push(callback)
}
//请求拦截器
http.interceptors.request.use(config => {
config.data = config.data || {};
// 可以在这里添加全局统一的关卡 比如说token userid等等
// 判断是否拥有登录有则添加到请求参数中去 也就是 data中去 这样只要请求就会带userid 与token,就不需要再在每个接口中写全局统一的参数
// const sessonToken = JSON.parse(sessionStorage.getItem('state')) || null
let token = store.state.accessToken;
if (token) {
config.headers = store.state.headers;
}
if (isTokenExpired() && !config.url.includes("Token") && token) {
// 如果token快过期了
if (!isRefreshing) { // 控制重复获取token
isRefreshing = true
const UserInfo = {
refreshToken: store.state.refreshToken,
userId: store.state.userId,
}
axios.request({
baseURL: APIURL,
method: 'get',
url: 'Token',
params: {
refreshToken: UserInfo.refreshToken,
id: UserInfo.userId
}
}).then(res => {
isRefreshing = false
if (res && res.data.code === 0) {
const result = res.data.data;
let info = {};
// token存储到vuex
if (result) {
info = {
accessToken: result["accessToken"],
refreshToken: result["refreshToken"],
accessTokenExpiresIn: result["accessTokenExpiresIn"],
userId: result["userId"],
};
//token存储本地
store.commit("initToken", info);
onAccessTokenFetched(info.accessToken)
}
}
}).catch(() => {
router.push({ path: '/login' })// 失败就跳转登陆
isRefreshing = false
})
}
// 将其他接口缓存起来 -- 这个Promise函数很关键
const retryRequest = new Promise((resolve) => {
// 这里是将其他接口缓存起来的关键, 返回Promise并且让其状态一直为等待状态,
// 只有当token刷新成功后, 就会调用通过addSubscriber函数添加的缓存接口,
// 此时, Promise的状态就会变成resolve
addSubscriber((newToken) => {
// 表示用新的token去替换掉原来的token
config.headers.Authorization = 'Bearer ' + newToken
// 替换掉url -- 因为baseURL会扩展请求url
config.url = config.url.replace(config.baseURL, '')
// 返回重新封装的config, 就会将新配置去发送请求
resolve(config)
})
})
return retryRequest
}
//显示加载
showFullScreenLoading();
// 最后return config
return config;
}, function (error) {
return Promise.reject(error);
});