import axios from 'axios' import $qxueyou from '@/config/qxueyou.js' import { getUUID } from "@/utils/tool.js"; import { ElMessage } from 'element-plus'; import router from '@/router/index.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; } } //网络请求监听 createAxios.interceptors.request.use( function(config) { // 刷新 token 的请求不需要添加 Authorization header if (!config.url.includes('/auth/refresh-token')) { config.headers = { ...config.headers, Authorization: localStorage.getItem(ACCESS_TOKEN_KEY) } } config.flag = getUUID().toString().slice(-4) if (config.data) { console.log(`data-${config.flag} `, config.data) } if (config.params) { console.log(`params-${config.flag} `, 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(`url-${response.config.flag}`, response.config.url, 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(); } finally { isRefreshing = false; } } else { tokenUtils.clearTokens(); } } console.log(`url-${response.config.flag} `, response.config.url, response.data) return response }, error => { if (!error.response) return Promise.reject(error) if (401 === error.response.status) { // 刷新 token 的请求返回 401 时,直接返回错误,不要抛出新的错误 if (error.config && error.config.url && error.config.url.includes('/auth/refresh-token')) { return Promise.reject(error) } throw new Error('登录失效') } ElMessage.error(error) return Promise.reject(error) } ) export default createAxios