mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-03-03 00:00:58 +08:00
feat(api): 兼容多种后端API响应风格
- 在环境变量中新增VITE_GLOB_API_STYLE配置项以支持auto、furion和abp三种响应风格 - 在全局类型定义中添加apiStyle字段,支持对应响应风格类型约束 - request.ts中实现Furion风格响应判断和自动切换ABP风格处理逻辑 - 增加ABP风格错误处理,包含401/403自动登出及验证错误提示 - ABP风格下支持HTTP 200直接成功返回数据和不同成功提示模式 - use-app-config.ts中添加apiStyle配置读取及默认值逻辑 - 注释掉YiAbpWebModule中Furion统一响应API的启用代码,改为默认使用ABP风格
This commit is contained in:
@@ -6,3 +6,6 @@ VITE_APP_NAMESPACE=vben-web-antd
|
||||
|
||||
# 对store进行加密的密钥,在将store持久化到localStorage时会使用该密钥进行加密
|
||||
VITE_APP_STORE_SECURE_KEY=please-replace-me-with-your-own-key
|
||||
|
||||
# API响应风格: auto(自动检测) | furion | abp
|
||||
VITE_GLOB_API_STYLE=auto
|
||||
|
||||
@@ -27,11 +27,29 @@ import {
|
||||
} from '#/utils/encryption/crypto';
|
||||
import * as encryptUtil from '#/utils/encryption/jsencrypt';
|
||||
|
||||
const { apiURL, clientId, enableEncrypt, demoMode } = useAppConfig(
|
||||
const { apiURL, clientId, enableEncrypt, demoMode, apiStyle } = useAppConfig(
|
||||
import.meta.env,
|
||||
import.meta.env.PROD,
|
||||
);
|
||||
|
||||
/** 判断是否为 Furion 风格响应 */
|
||||
function isFurionResponse(data: any): boolean {
|
||||
return (
|
||||
data != null &&
|
||||
typeof data === 'object' &&
|
||||
'statusCode' in data &&
|
||||
'succeeded' in data
|
||||
);
|
||||
}
|
||||
|
||||
/** 判断当前响应是否应按 ABP 风格处理 */
|
||||
function shouldUseAbpStyle(data: any): boolean {
|
||||
if (apiStyle === 'abp') return true;
|
||||
if (apiStyle === 'furion') return false;
|
||||
// auto: 不是 Furion 结构就按 ABP 处理
|
||||
return !isFurionResponse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已经处在登出过程中了 一个标志位
|
||||
* 主要是防止一个页面会请求多个api 都401 会导致登出执行多次
|
||||
@@ -180,6 +198,47 @@ function createRequestClient(baseURL: string) {
|
||||
if (error?.__isDemoModeError || error?.name === 'DemoModeException') {
|
||||
return;
|
||||
}
|
||||
|
||||
const status = error?.response?.status;
|
||||
const responseData = error?.response?.data;
|
||||
const abpError = responseData?.error;
|
||||
|
||||
// 判断是否为 ABP 风格错误
|
||||
const isAbp =
|
||||
apiStyle === 'abp' ||
|
||||
(apiStyle === 'auto' &&
|
||||
abpError &&
|
||||
typeof abpError.message === 'string');
|
||||
|
||||
if (isAbp) {
|
||||
// ABP 401/403 需要触发登出
|
||||
if ((status === 401 || status === 403) && !isLogoutProcessing) {
|
||||
isLogoutProcessing = true;
|
||||
const _msg = abpError?.message || msg;
|
||||
const userStore = useAuthStore();
|
||||
userStore.logout().finally(() => {
|
||||
message.error(_msg);
|
||||
isLogoutProcessing = false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// ABP 其他错误:提取 error.message,拼接 validationErrors
|
||||
let errorMsg = abpError?.message || msg;
|
||||
if (abpError?.validationErrors?.length) {
|
||||
const details = abpError.validationErrors
|
||||
.map((e: any) => e.message)
|
||||
.filter(Boolean)
|
||||
.join('; ');
|
||||
if (details) {
|
||||
errorMsg = `${errorMsg}: ${details}`;
|
||||
}
|
||||
}
|
||||
message.error(errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Furion 风格 / 非 ABP:保持原有行为
|
||||
message.error(msg);
|
||||
},
|
||||
);
|
||||
@@ -234,6 +293,20 @@ function createRequestClient(baseURL: string) {
|
||||
throw new Error($t('http.apiRequestFailed'));
|
||||
}
|
||||
|
||||
// ABP 风格:HTTP 200 即成功,直接返回数据
|
||||
if (shouldUseAbpStyle(axiosResponseData)) {
|
||||
if (response.config.successMessageMode === 'modal') {
|
||||
Modal.success({
|
||||
content: $t('http.operationSuccess'),
|
||||
title: $t('http.successTip'),
|
||||
});
|
||||
} else if (response.config.successMessageMode === 'message') {
|
||||
message.success($t('http.operationSuccess'));
|
||||
}
|
||||
return axiosResponseData;
|
||||
}
|
||||
|
||||
// Furion 风格响应处理
|
||||
console.log('axiosResponseData', axiosResponseData);
|
||||
// 适配后端数据结构: { statusCode, data, succeeded, errors, extras, timestamp }
|
||||
const { statusCode, data, succeeded, errors, extras, timestamp } =
|
||||
|
||||
@@ -23,6 +23,7 @@ export function useAppConfig(
|
||||
VITE_GLOB_RSA_PUBLIC_KEY,
|
||||
VITE_GLOB_SSE_ENABLE,
|
||||
VITE_GLOB_DEMO_MODE,
|
||||
VITE_GLOB_API_STYLE,
|
||||
} = config;
|
||||
|
||||
return {
|
||||
@@ -39,5 +40,9 @@ export function useAppConfig(
|
||||
sseEnable: VITE_GLOB_SSE_ENABLE === 'false',
|
||||
// 是否开启演示模式
|
||||
demoMode: VITE_GLOB_DEMO_MODE === 'true',
|
||||
// API响应风格
|
||||
apiStyle: (['abp', 'furion'].includes(VITE_GLOB_API_STYLE)
|
||||
? VITE_GLOB_API_STYLE
|
||||
: 'auto') as 'abp' | 'auto' | 'furion',
|
||||
};
|
||||
}
|
||||
|
||||
4
Yi.Vben5.Vue3/packages/types/global.d.ts
vendored
4
Yi.Vben5.Vue3/packages/types/global.d.ts
vendored
@@ -22,6 +22,8 @@ export interface VbenAdminProAppConfigRaw {
|
||||
VITE_GLOB_SSE_ENABLE: string;
|
||||
// 是否开启演示模式(只读模式,禁止修改操作) 注意从配置文件获取的类型为string
|
||||
VITE_GLOB_DEMO_MODE: string;
|
||||
// API响应风格: auto(自动检测) | furion | abp
|
||||
VITE_GLOB_API_STYLE: string;
|
||||
}
|
||||
|
||||
export interface ApplicationConfig {
|
||||
@@ -39,6 +41,8 @@ export interface ApplicationConfig {
|
||||
sseEnable: boolean;
|
||||
// 是否开启演示模式(只读模式,禁止修改操作)
|
||||
demoMode: boolean;
|
||||
// API响应风格
|
||||
apiStyle: 'abp' | 'auto' | 'furion';
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
Reference in New Issue
Block a user