axios 刷新 token

  • 刷新 token,保持登录
// 计算是否快要过期
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);
});
posted @ 2022-07-29 09:36  DL·Coder  阅读(374)  评论(0编辑  收藏  举报