import FingerprintJS from '@fingerprintjs/fingerprintjs'; import { ElMessage } from 'element-plus'; import hookFetch from 'hook-fetch'; import { sseTextDecoderPlugin } from 'hook-fetch/plugins'; import router from '@/routers'; import { useUserStore } from '@/stores'; // 初始化指纹 const fpPromise = FingerprintJS.load(); async function getFingerprint(): Promise { const fp = await fpPromise; return (await fp.get()).visitorId; } interface BaseResponse { code?: number; // 变为可选字段 data: T; msg?: string; } declare module 'hook-fetch' { interface HookFetchDefaults { response: any; } } // 刷新控制变量 let isRefreshing = false; let pendingRequests: (() => void)[] = []; export const request = hookFetch.create({ baseURL: import.meta.env.VITE_WEB_BASE_API, headers: { 'Content-Type': 'application/json', }, plugins: [ sseTextDecoderPlugin({ json: true, prefix: 'data:' }), { name: 'fingerprint-plugin', beforeRequest: async (config) => { try { const fingerprint = await getFingerprint(); config.headers = new Headers(config.headers); config.headers.set('X-Fingerprint', fingerprint); } catch (error) { console.error('指纹生成失败:', error); } return config; }, }, { name: 'jwt-auth', beforeRequest: (config) => { const userStore = useUserStore(); if (userStore.token) { config.headers = new Headers(config.headers); config.headers.set('Authorization', `Bearer ${userStore.token}`); } return config; }, afterResponse: async (response: any, config: any) => { const userStore = useUserStore(); console.log('网络请求响应----', response); // 成功请求(HTTP状态码200-299) if (response.ok) { // 兼容响应体可能没有code字段的情况 const data = await response.json(); return { ...response, result: data.code ? data : { code: 200, data, msg: 'success' }, }; } // 处理HTTP状态码401 if (response.status === 401) { // 刷新Token接口自身失败 if (config.url?.includes('/account/refresh')) { userStore.logout(); userStore.openLoginDialog(); throw new Error('刷新Token失败'); } // 将请求加入队列 if (isRefreshing) { return new Promise((resolve) => { pendingRequests.push(() => resolve(request(config))); }); } // 开始刷新流程 isRefreshing = true; try { const refreshRes = await request.post('/account/refresh', { refresh_token: userStore.refreshToken, }).json(); // 更新Token userStore.setToken(refreshRes.data.token, refreshRes.data.refreshToken); // 重试原始请求 config.headers.set('Authorization', `Bearer ${refreshRes.data.token}`); const retryResponse = await request(config); // 执行等待中的请求 pendingRequests.forEach(cb => cb()); pendingRequests = []; return retryResponse; } catch (error) { // 刷新失败清除状态 userStore.logout(); userStore.openLoginDialog(); throw error; } finally { isRefreshing = false; } } // 处理HTTP状态码403 if (response.status === 403) { router.replace({ name: '403' }); const errorMsg = (await response.json().catch(() => ({})))?.msg || '无权限访问'; ElMessage.error(errorMsg); throw new Error('Forbidden'); } // 其他错误状态码 const errorData = await response.json().catch(() => ({})); ElMessage.error(errorData.msg || `请求失败: ${response.status}`); throw errorData; }, // 错误处理 async onError(error: any, config: any) { console.log('网络请求错误----', error); console.log('网络请求错误--config--', config); // 可以处理或转换错误 if (error.status === 401) { // 处理未授权错误 return new Error('Please login first'); } return error; }, }, ], }); // 保持原有导出 export const post = request.post; export const get = request.get; export const put = request.put; export const del = request.delete; export default request;