import axios from 'axios' import $qxueyou from '@/config/qxueyou.js' import { getUUID } from "@/utils/tool.js"; let createAxios = axios.create({ baseURL: $qxueyou.serverRoot, timeout: 30000, headers: { "Content-Type": `application/json;charset=utf-8` } }) createAxios.all = axios.all createAxios.spread = axios.spread // Token 工具函数 const ACCESS_TOKEN_KEY = $qxueyou.ACCESS_TOKEN_KEY; const REFRESH_TOKEN_KEY = $qxueyou.REFRESH_TOKEN_KEY; export const tokenUtils = { // 获取 Access Token getAccessToken() { return localStorage.getItem(ACCESS_TOKEN_KEY); }, // 获取 Refresh Token getRefreshToken() { return localStorage.getItem(REFRESH_TOKEN_KEY); }, // 设置 Token setTokens(accessToken, refreshToken) { if (accessToken) { localStorage.setItem(ACCESS_TOKEN_KEY, accessToken); } if (refreshToken) { localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken); } }, // 清除 Token clearTokens() { localStorage.removeItem(ACCESS_TOKEN_KEY); localStorage.removeItem(REFRESH_TOKEN_KEY); }, // 检查 Token 是否存在 hasTokens() { return !!(this.getAccessToken() && this.getRefreshToken()); }, } let isRefreshing = false; // 刷新 token 期间的请求队列 let refreshQueue = []; // 刷新 Access Token export async function refreshAccessToken() { const currentRefreshToken = tokenUtils.getRefreshToken(); if (!currentRefreshToken) { throw new Error("No refresh token available"); } try { const response = await createAxios.post( `/system/auth/refresh-token?refreshToken=${currentRefreshToken}` ); if (response.data && response.data.code === 0) { const { accessToken, refreshToken: newRefreshToken } = response.data.data; tokenUtils.setTokens(accessToken, newRefreshToken); return accessToken; } else { throw new Error("Token refresh failed"); } } catch (error) { console.error('Token refresh error:', error); throw error; } } let strTrim = function(data) { let newData = {...data} Object.keys(newData).forEach((key) => { if (typeof newData[key] === 'string') { newData[key] = newData[key].trim() } }) return newData } //网络请求监听 createAxios.interceptors.request.use( function(config) { // 刷新 token 的请求不需要添加 Authorization header if (!config.url.includes('/auth/refresh-token')) { config.headers = { ...config.headers, Authorization: localStorage.getItem('accessToken') } } config.flag = getUUID().toString().slice(-4) if (config.data) { console.log(`data-${config.flag} `, config.data) // config.data = JSON.stringify(config.data) } if (config.params) { console.log(`params-${config.flag} `, config.params) // config.params = strTrim(config.params) } return config }, function(error) { return Promise.reject(error) } ) createAxios.interceptors.response.use( async response => { const resultCode = response.data.code; const originalRequest = response.config; if (response.data && [500, 400].includes(resultCode)) { console.log(response) return response } if (response.data && resultCode == '401') { if (!originalRequest._retry && tokenUtils.getRefreshToken) { originalRequest._retry = true; if (isRefreshing) { // 如果正在刷新,将请求加入队列 return new Promise((resolve, reject) => { refreshQueue.push({ resolve, reject, config: originalRequest }); }); } isRefreshing = true; try { const newAccessToken = await refreshAccessToken(); // 处理队列中的请求 refreshQueue.forEach(({ resolve, config }) => { config.headers.Authorization = newAccessToken; resolve(createAxios(config)); }); refreshQueue = []; // 重新发送原始请求 originalRequest.headers.Authorization = newAccessToken; return createAxios(originalRequest) } catch (refreshError) { console.log(refreshError) // 刷新失败,处理队列中的请求 refreshQueue.forEach(({ reject }) => { reject(refreshError); }); refreshQueue = []; tokenUtils.clearTokens(); // $store.commit("session/loginFlag", false); // $store.commit("session/userInfo", {}); // 可以在这里触发登录页面跳转 } finally { isRefreshing = false; } } else { tokenUtils.clearTokens(); // $store.commit("session/loginFlag", false); // $store.commit("session/userInfo", {}); } } console.log(`url-${response.config.flag} `, response.config.url, response.data) return response }, error => { // store.commit('network/changeNetworkState', false) if (!error.response) return Promise.reject(error) // store.commit('network/status', error.response.status) if (401 === error.response.status) { // 刷新 token 的请求返回 401 时,直接返回错误,不要抛出新的错误 if (error.config && error.config.url && error.config.url.includes('/auth/refresh-token')) { return Promise.reject(error) } // store.commit('session/clearUser') // store.commit('endea/clearShareK') // store.commit('network/logout') throw new Error('登录失效') } return Promise.reject(error) } ) export default createAxios