1.类型申明
javascript
declare namespace ApiContract {
// 响应结果类型
interface Result<T> {
success: boolean;
code: string;
message: string;
data: T;
extension: Record<string, any>;
}
// 响应结果包装类型
interface ResultWrapper<T> {
data: T;
result?: Result<T>;
response?: any;
}
// Promise响应结果包装类型
type PromiseResultWrapper<T> = Promise<ApiContract.ResultWrapper<T>>;
// 状态码处理函数定义
type StatusHandler<T> = (result: Result<T>) => void;
// 状态处理函数映射类型
type StatusKey = string | 'ALL_FAIL'
interface StatusHandlerMapping<T> extends Record<StatusKey, StatusHandler<T>> {
}
}
豆包代码解读:
好的,这段代码是 TypeScript 中的一个接口定义,它主要用于处理 HTTP 请求响应结果,以下是对代码的详细解释:
-
Result<T>
接口:success
: 一个布尔类型的属性,用来表示请求是否成功。code
: 一个字符串类型的属性,通常用来表示响应的状态码。message
: 一个字符串类型的属性,用来提供额外的信息,通常是对请求结果的描述。data
: 一个泛型类型T
的属性,用来存储请求成功时返回的数据。extension
: 一个对象类型的属性,用来存储任何额外的扩展信息,通常包含一些元数据或其他数据。
-
ResultWrapper<T>
接口:data
: 一个泛型类型T
的属性,用来存储请求成功时返回的数据,与Result<T>
中的data
属性类似。result
: 一个可选的Result<T>
类型属性,用来包含原始的响应结果对象。response
: 一个可选的属性,用来存储原始的 HTTP 响应对象,供开发者用来查看原始的响应数据。
可以看出,
ResultWrapper<T>
接口类是对Result<T>
接口的扩展,主要用于在Result<T>
接口的基础上添加了额外的属性,以方便开发者对响应结果进行进一步处理。 -
PromiseResultWrapper<T>
类型别名:- 在这里代表一个返回值为
Promise
对象,最终解析为ResultWrapper<T>
类型的异步操作。这个类型别名通常用于表示网络请求或者其他异步操作的结果。
- 在这里代表一个返回值为
-
StatusHandler<T>
类型别名:- 这是一个函数类型别名,它接受一个
Result<T>
类型的参数result
。这个类型别名通常用于定义处理特定状态码的函数。
- 这是一个函数类型别名,它接受一个
-
StatusKey
类型别名:- 在这里表示一个字符串类型或一个特定的字符串
ALL_FAIL
,它通常用于表示状态码处理函数的键值。
- 在这里表示一个字符串类型或一个特定的字符串
-
StatusHandlerMapping<T>
接口:- 这是一个继承自
Record<StatusKey, StatusHandler<T>>
的接口。它允许你为不同的状态键定义处理函数。这样,你可以根据响应结果的状态码来调用相应的处理函数。
- 这是一个继承自
总的来看,这些定义提供了一个灵活的框架,用于定义和处理异步操作的结果,特别是在处理 HTTP 请求响应时。它们提供了一种标准化的方式来处理成功和失败的情况,并允许开发者定制响应状态码的处理逻辑。
2.业务状态处理拦截
javascript
import { AxiosResponse } from 'axios';
import { message as alter } from 'antd';
import { debounce } from '@utils/common';
export const ALL_FAIL = 'ALL_FAIL';
const alertMessage = debounce((message: string) => {
alter.error(message, 3).then();
}, 500);
// 结果业务拦截器
export const businessStatusInterceptor = function <T>(
axiosPromise: Promise<AxiosResponse>,
statusHandlerMapping?: ApiContract.StatusHandlerMapping<T>
): Promise<ApiContract.ResultWrapper<T>> {
const shm = statusHandlerMapping;
return new Promise((resolve, reject) => {
axiosPromise.then((response) => {
const result = response.data as ApiContract.Result<T>;
const { success, code, message, data } = result;
const businessResult: ApiContract.ResultWrapper<T> = {
data,
result,
response,
};
// 是否成功
if (success) {
resolve(businessResult);
} else {
reject({
isBusinessError: true,
businessResult
});
}
// 状态处理
if (shm && (shm[ALL_FAIL] || (shm[code] && typeof shm[code] === 'function'))) {
const failHandler = shm[ALL_FAIL];
try {
(failHandler || shm[code])(result);
} catch (ignored) {
}
} else if (!success) {
alter.error(message, 3).then();
}
}).catch((error) => {
alertMessage("哎呀! 服务器出现异常");
reject({
isBusinessError: false,
message: error.code,
});
})
});
}
豆包代码解读:
这段代码是一个 JavaScript 函数,它是一个 Promise 的解析器,用于处理异步操作的结果。它接收一个 Promise 对象和一个可选的状态处理映射对象作为参数。函数的主要目的是根据 Promise 的解析结果来确定业务逻辑的处理方式,同时提供了一种机制来处理特定的错误状态。
下面是对代码的详细解释:
- 首先,代码使用
const shm = statusHandlerMapping;
来创建statusHandlerMapping
的引用,以便后续使用。 - 在
promise.then((response) => {...})
内部,代码获取响应对象并将其解析为ApiContract.Result<T>
类型。它提取Result
对象的属性,如success
、code
、message
和data
,并创建一个businessResult
对象,其中包含这些属性。 - 接收到数据之后,根据
success
属性判断请求是否成功。如果请求成功,函数将businessResult
对象作为解析后的 Promise 的值,并调用resolve(businessResult)
。这样,调用这个函数的人就可以通过处理这个 Promise 获取到成功的响应数据。 - 如果请求失败,代码调用
reject({...})
来拒绝 Promise,返回一个包含isBusinessError: true
和businessResult
属性的对象。这样,调用这个函数的人就可以捕获到失败的响应,并处理相应的错误逻辑。 - 然后,代码检查是否存在状态处理映射对象
shm
,并且 shm 中是否定义了针对所有错误的处理函数shm[ALL_FAIL]
,或者是否定义了针对特定错误码的处理函数shm[code]
。如果存在这样的处理函数,代码尝试执行它们。这提供了一种灵活的方式来处理特定的错误场景,例如,当服务器返回特定的错误码时,可以执行特定的警告或其他操作。 - 如果既没有成功也没有 definition 的处理函数,代码将显示一个错误消息,使用
antd
的alert.error
组件来展示错误信息。 - 在 Promise 的捕获块
catch((error) => {...})
中,代码处理 Promise 链中的任何错误。它调用alertMessage
函数来显示一条服务器异常的错误消息,然后调用reject({...})
来拒绝 Promise。这里返回一个包含isBusinessError: false
和message: error.code
属性的对象。调用这个函数的人可以根据isBusinessError
属性来判断错误是业务逻辑错误还是服务器异常,并且可以根据message
属性获取错误码来进行后续处理。
总的来说,这段代码用于处理 Promise 的解析,并根据服务器响应中的 success
属性、code
属性和 statusHandlerMapping
对象来处理业务逻辑中的成功、失败和特定错误状态。它旨在提供一种标准化的方式来处理异步操作的结果,同时允许开发者定制响应状态的处理逻辑。
3.请求封装
javascript
import axios, { AxiosRequestConfig } from 'axios';
import { message as alter } from 'antd';
import { businessStatusInterceptor, ALL_FAIL as ALL_FAIL_CODE } from '@contract/api';
// 设置后端路径
axios.defaults.baseURL = 'http://localhost:8082';
export namespace ApiCommon {
// 常量
export const SUCCESS_CODE = '0';
export const ALL_FAIL = ALL_FAIL_CODE;
// 默认分页数据
export const initialPage: API.PageParam = {
pageNo: 1,
pageSize: 10,
};
// then catch处理工具
export const alertThen = (resultWrapper: ApiContract.ResultWrapper<any>) => {
alter.success(resultWrapper?.result?.message, 3).then();
}
export const emptyThen = () => {
}
export const emptyCatch = emptyThen;
// 选项
export interface Options<T> extends AxiosRequestConfig {
shm?: ApiContract.StatusHandlerMapping<T>;
}
/**
* Get请求
* @param path 路径
* @param params 参数
* @param options 请求配置
*/
export const get = function <P, R>(path: string, params?: P, options?: Options<R>) {
return businessStatusInterceptor<R>(axios.get(path, {
...options,
params,
}), options?.shm);
}
/**
* Post请求
* @param path 路径
* @param data 参数
* @param options 请求配置
*/
export const post = function <P, R>(path: string, data?: P, options?: Options<R>) {
return businessStatusInterceptor(axios.post(path, data, {
...options,
}), options?.shm);
}
/**
* Put请求
* @param path 路径
* @param data 参数
* @param options 请求配置
*/
export const put = function <P, R>(path: string, data?: P, options?: Options<R>) {
return businessStatusInterceptor(axios.put(path, data, {
...options,
}), options?.shm);
}
/**
* FromData请求
* @param path 路径
* @param fromData 参数
* @param options 请求配置
*/
export const fromData = function <P, R>(path: string, fromData?: P, options?: Options<R>) {
return businessStatusInterceptor(axios.post(path, fromData, {
...options,
}), options?.shm);
}
/**
* Delete请求
* @param path 路径
* @param params 参数
* @param options 请求配置
*/
export const del = function <P, R>(path: string, params?: P, options?: Options<R>) {
return businessStatusInterceptor(axios.delete(path, {
...options,
params,
}), options?.shm);
}
// 请求装饰
export type RequestHandler<P, R> = (param?: P, options?: Options<R>) => Promise<ApiContract.ResultWrapper<R>>;
export const decorateRequest = <P, R>(handler: RequestHandler<P, R>) => {
return (param?: P, shm?: ApiContract.StatusHandlerMapping<R>, requestConfig?: AxiosRequestConfig): Promise<ApiContract.ResultWrapper<R>> => {
const options = {
...requestConfig,
shm,
} as Options<R>;
return handler && typeof handler === 'function' ? handler(param, options) : Promise.reject(undefined);
}
}
}
export default ApiCommon;
豆包代码解读:
ApiCommon
是一个对象,它包含了一些与 API 调用相关的常量、工具函数和和不同类型的请求方法(如 GET、POST、PUT、DELETE 等),并对请求结果基于业务状态做了处理。以下是对代码的详细解释:
常量
SUCCESS_CODE
:定义了一个名为SUCCESS_CODE
的常量,并赋值为字符串'0'
,这个常量可能用于表示 API 调用成功的状态码。ALL_FAIL
:引入了一个名为ALL_FAIL_CODE
的常量,可能用于表示所有失败情况的错误码。
工具函数
alertThen
和emptyThen
:分别用于处理 Promise 链中的成功和失败。alertThen
函数使用antd
的alert.error
组件来展示错误信息。emptyThen
函数为空,可能作为默认的成功或失败处理逻辑。
请求方法
get
、post
、put
、fromData
和del
:请求方法,它们封装了axios.get
、axios.post
、axios.put
、axios.delete
方法,用于发起不同类型的 HTTP 请求。这些函数是泛型的,允许指定请求的参数类型P
和响应类型R
。请求配置对象Options<R>
允许为每个请求指定特定的状态处理映射对象shm
。
请求装饰器
decorateRequest
:这个函数是一个装饰器,用于装饰请求处理器RequestHandler<P, R>
。装饰器的目的是为请求处理器赋予额外的功能,或者改变它们的行为。在这个特定的装饰器中,它允许为请求处理器提供额外的配置选项。这个装饰器函数实际上创建了一个新的函数,这个新函数被赋予了参数param
、shm
和requestConfig
。这个新函数内部通过handler(param, options)
来调用原始请求处理器,并将这三个参数传递给它。这里的options
对象是通过合并requestConfig
和shm
创建的,确保原始请求处理器能够访问这些配置信息。
请求拦截器
businessStatusInterceptor
:这个拦截器函数用于拦截axios
请求,并根据ApiContract.ResultWrapper<T>
格式对响应进行处理。当请求成功时,它会直接返回一个包含响应数据的Promise
。当请求失败时,它会检查statusHandlerMapping
中是否存在针对特定错误码的处理函数。如果存在这样的处理函数,它会执行这些函数,并将错误信息传递给它们。如果没有处理函数,它会显示一个错误信息,并返回一个包含错误信息的Promise
。
默认分页数据
initialPage
:定义了默认分页数据,这对于需要分页显示数据的场景可能非常有用。
模块导出
export default ApiCommon;
:将ApiCommon
对象导出为默认导出,这样在其他地方导入这个模块时,就可以直接使用ApiCommon
对象。
总的来说,ApiCommon
对象提供了一个封装了各种 API 请求方法的中央存储库,可以轻松地管理和维护应用程序中的 HTTP 请求逻辑。
4.接口定义
javascript
// 校验数据源连接
export const testConnection = ApiCommon.decorateRequest<TestConnectionParam, void>((param, options) => {
return ApiCommon.post(`/v1/data-source/test-connection`, { ...param }, options);
});
5.使用
javascript
DataSourceApi.testConnection(param, {
'50001': ({ message }) => {
// 业务状态码code为50001时执行的逻辑, 将覆盖默认错误处理逻辑(alertMessage)
setSubmitBtnStatus(false);
setTestMessage(<strong style={{ color: '#f50' }}>{message}</strong>);
}
})
.then(() => {
// 业务结果返回成功时执行的逻辑
setSubmitBtnStatus(true);
setTestMessage(<strong style={{ color: '#87d068' }}>Success</strong>);
})
.catch(ApiCommon.emptyCatch)
.finally(() => {
setTestLoading(false);
});