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:
dubai
2026-02-12 00:43:52 +08:00
parent 92064cc4f5
commit d00cdcf122
4 changed files with 86 additions and 1 deletions

View File

@@ -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

View File

@@ -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 } =

View File

@@ -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',
};
}

View File

@@ -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 {