Browse Source

feat(request): 落地统一响应字段约定 ResultFieldEnum

- 新增 ResultFieldEnum(code/data/message),响应字段名统一收敛到 @vben/constants
- 三个预置拦截器默认值与业务 code 读取改用枚举,并透传 codeField 配置支持自定义字段
- 补充各拦截器的方法级 JSDoc 与参数注释
pull/8337/head
雪忆天堂 4 weeks ago
parent
commit
ccc49a2482
  1. 5
      apps/web-antd/src/api/request.ts
  2. 5
      apps/web-antdv-next/src/api/request.ts
  3. 5
      apps/web-ele/src/api/request.ts
  4. 5
      apps/web-naive/src/api/request.ts
  5. 5
      apps/web-tdesign/src/api/request.ts
  6. 5
      docs/src/en/guide/essentials/server.md
  7. 5
      docs/src/guide/essentials/server.md
  8. 7
      packages/constants/src/http.enum.ts
  9. 41
      packages/effects/request/src/request-client/preset-interceptors.ts
  10. 5
      playground/src/api/request.ts

5
apps/web-antd/src/api/request.ts

@ -3,6 +3,7 @@
*/
import type { RequestClientOptions } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -89,10 +90,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

5
apps/web-antdv-next/src/api/request.ts

@ -3,6 +3,7 @@
*/
import type { RequestClientOptions } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -89,10 +90,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

5
apps/web-ele/src/api/request.ts

@ -3,6 +3,7 @@
*/
import type { RequestClientOptions } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -89,10 +90,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
ElMessage.error(errorMessage || msg);
}),

5
apps/web-naive/src/api/request.ts

@ -3,6 +3,7 @@
*/
import type { RequestClientOptions } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -88,10 +89,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

5
apps/web-tdesign/src/api/request.ts

@ -3,6 +3,7 @@
*/
import type { RequestClientOptions } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -88,10 +89,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

5
docs/src/en/guide/essentials/server.md

@ -167,6 +167,7 @@ The `src/api/request.ts` within the application can be configured according to t
*/
import type { HttpResponse } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -259,10 +260,10 @@ function createRequestClient(baseURL: string) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

5
docs/src/guide/essentials/server.md

@ -197,6 +197,7 @@ export async function deleteUserApi(userId: number) {
*/
import type { HttpResponse } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -290,10 +291,10 @@ function createRequestClient(baseURL: string) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

7
packages/constants/src/http.enum.ts

@ -38,6 +38,13 @@ export enum HttpResultEnum {
WARN = 601,
}
/** 返回结果字段 */
export enum ResultFieldEnum {
CODE = 'code',
DATA = 'data',
MESSAGE = 'message',
}
/**
* @description: request method
*/

41
packages/effects/request/src/request-client/preset-interceptors.ts

@ -1,15 +1,18 @@
import type { RequestClient } from './request-client';
import type { MakeErrorMessageFn, ResponseInterceptorConfig } from './types';
import { HttpResultEnum } from '@vben/constants';
import { HttpResultEnum, ResultFieldEnum } from '@vben/constants';
import { $t } from '@vben/locales';
import { isFunction } from '@vben/utils';
import axios from 'axios';
/**
* 默认的响应数据格式化拦截器,根据业务状态码判断请求是否成功,并提取需要返回的数据
*/
export const defaultResponseInterceptor = ({
codeField = 'code',
dataField = 'data',
codeField = ResultFieldEnum.CODE,
dataField = ResultFieldEnum.DATA,
successCode = HttpResultEnum.SUCCESS,
}: {
/** 响应数据中代表访问结果的字段名 */
@ -19,16 +22,6 @@ export const defaultResponseInterceptor = ({
/** 当codeField所指定的字段值与successCode相同时,代表接口访问成功。如果提供一个函数,则返回true代表接口访问成功 */
successCode?: ((code: any) => boolean) | number | string;
}): ResponseInterceptorConfig => {
// 初始化字段
if (!codeField) {
codeField = 'code';
}
if (!dataField) {
dataField = 'data';
}
if (!successCode) {
successCode = HttpResultEnum.SUCCESS;
}
return {
fulfilled: (response) => {
const { config, data: responseData, status } = response;
@ -55,24 +48,35 @@ export const defaultResponseInterceptor = ({
};
};
/**
* 认证拦截器,处理401未授权错误:优先尝试刷新token并重发请求,失败则触发重新认证
*/
export const authenticateResponseInterceptor = ({
client,
doReAuthenticate,
doRefreshToken,
enableRefreshToken,
formatToken,
codeField = ResultFieldEnum.CODE,
}: {
/** 请求客户端实例,用于刷新token后重新发起请求 */
client: RequestClient;
/** 重新认证逻辑(token失效且无法刷新时触发,如跳转登录页) */
doReAuthenticate: () => Promise<void>;
/** 刷新token的逻辑 */
doRefreshToken: () => Promise<string>;
/** 是否启用刷新token功能 */
enableRefreshToken: boolean;
/** token格式化方法 */
formatToken: (token: string) => null | string;
/** 响应数据中代表访问结果的字段名 */
codeField?: string;
}): ResponseInterceptorConfig => {
return {
rejected: async (error) => {
const { config, response } = error;
// 如果不是 401 错误,直接抛出异常
const status = response?.data?.code || response?.status;
const status = response?.data?.[codeField] || response?.status;
if (status !== HttpResultEnum.UNAUTHORIZED) {
throw error;
}
@ -121,8 +125,14 @@ export const authenticateResponseInterceptor = ({
};
};
/**
* 通用的错误消息提示拦截器,根据响应状态码提示对应的错误信息
* @param makeErrorMessage - 统一的错误消息提示方法
* @param codeField - 响应数据中代表访问结果的字段名,可选
*/
export const errorMessageResponseInterceptor = (
makeErrorMessage?: MakeErrorMessageFn,
codeField: string = ResultFieldEnum.CODE,
): ResponseInterceptorConfig => {
return {
rejected: (error: any) => {
@ -143,7 +153,8 @@ export const errorMessageResponseInterceptor = (
}
let errorMessage: string;
const status = error?.response?.data?.code || error?.response?.status;
const status =
error?.response?.data?.[codeField] || error?.response?.status;
switch (status) {
case HttpResultEnum.REQUEST_TIMEOUT: {

5
playground/src/api/request.ts

@ -3,6 +3,7 @@
*/
import type { AxiosResponseHeaders, RequestClientOptions } from '@vben/request';
import { ResultFieldEnum } from '@vben/constants';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import {
@ -103,10 +104,10 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
client.addResponseInterceptor(
errorMessageResponseInterceptor((msg: string, error) => {
// 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg
// 当前mock接口返回的错误字段是 error 或者 message
// 默认从统一响应约定的 message 字段中提取错误信息,如后端使用其他字段(如 error、msg),可在此自定义
const responseData = error?.response?.data ?? {};
const errorMessage =
responseData?.error ?? responseData?.message ?? responseData?.msg ?? '';
responseData?.[ResultFieldEnum.MESSAGE] ?? responseData?.error ?? '';
// 如果没有错误信息,则会根据状态码进行提示
message.error(errorMessage || msg);
}),

Loading…
Cancel
Save