From d15e6e395bf4a5d8ca85418615afd5efbff905f0 Mon Sep 17 00:00:00 2001 From: Gsh <15170702455@163.com> Date: Sun, 29 Jun 2025 12:09:34 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=8B=A6=E6=88=AA?= =?UTF-8?q?=E5=99=A8=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Yi.Ai.Vue3/src/utils/request.ts | 163 +++++++++++------------------- Yi.Ai.Vue3/types/import_meta.d.ts | 1 + 2 files changed, 61 insertions(+), 103 deletions(-) diff --git a/Yi.Ai.Vue3/src/utils/request.ts b/Yi.Ai.Vue3/src/utils/request.ts index e65af17c..92ef1822 100644 --- a/Yi.Ai.Vue3/src/utils/request.ts +++ b/Yi.Ai.Vue3/src/utils/request.ts @@ -1,21 +1,26 @@ -import FingerprintJS from '@fingerprintjs/fingerprintjs'; +import type { HookFetchPlugin } from 'hook-fetch'; +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; + const { visitorId } = await fp.get(); + return visitorId; } +// 标准响应格式 interface BaseResponse { - code?: number; // 变为可选字段 + code: number; data: T; - msg?: string; + msg: string; } declare module 'hook-fetch' { @@ -24,10 +29,6 @@ declare module 'hook-fetch' { } } -// 刷新控制变量 -let isRefreshing = false; -let pendingRequests: (() => void)[] = []; - export const request = hookFetch.create({ baseURL: import.meta.env.VITE_WEB_BASE_API, headers: { @@ -36,7 +37,7 @@ export const request = hookFetch.create({ plugins: [ sseTextDecoderPlugin({ json: true, prefix: 'data:' }), { - name: 'fingerprint-plugin', + name: 'fingerprint-plugin', // 新增指纹插件 beforeRequest: async (config) => { try { const fingerprint = await getFingerprint(); @@ -44,110 +45,66 @@ export const request = hookFetch.create({ config.headers.set('X-Fingerprint', fingerprint); } catch (error) { - console.error('指纹生成失败:', error); + console.error('Failed to generate fingerprint:', 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}`); + name: 'adapt-array-response', + afterResponse: async (response) => { + if (typeof response.result?.code === 'number') { + return response; } - 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; + return { + ...response, + result: { + code: 200, + data: response.result, + msg: 'success', + }, + }; }, }, ], }); -// 保持原有导出 +// JWT插件(保持原有逻辑) +function jwtPlugin(): HookFetchPlugin { + const userStore = useUserStore(); + return { + name: 'jwt', + beforeRequest: async (config) => { + if (userStore.token) { + config.headers = new Headers(config.headers); + config.headers.set('authorization', `Bearer ${userStore.token}`); + } + return config; + }, + afterResponse: async (response) => { + if (response.result?.code === 200) + return response; + + if (response.result?.code === 403) { + router.replace({ name: '403' }); + ElMessage.error(response.result?.msg); + return Promise.reject(response); + } + + if (response.result?.code === 401) { + userStore.logout(); + userStore.openLoginDialog(); + } + + ElMessage.error(response.result?.msg); + return Promise.reject(response); + }, + }; +} + +request.use(jwtPlugin()); + +// 导出方法(保持原有) export const post = request.post; export const get = request.get; export const put = request.put; diff --git a/Yi.Ai.Vue3/types/import_meta.d.ts b/Yi.Ai.Vue3/types/import_meta.d.ts index 727544a9..5a851c00 100644 --- a/Yi.Ai.Vue3/types/import_meta.d.ts +++ b/Yi.Ai.Vue3/types/import_meta.d.ts @@ -6,6 +6,7 @@ interface ImportMetaEnv { readonly VITE_WEB_ENV: string; readonly VITE_WEB_BASE_API: string; readonly VITE_API_URL: string; + readonly VITE_BUILD_COMPRESS: string; readonly VITE_SSO_SEVER_URL: string; readonly VITE_SSO_CLIENT_ID: string; }