前端请求工具封装

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 对象的属性,如 successcodemessagedata,并创建一个 businessResult 对象,其中包含这些属性。
  • 接收到数据之后,根据 success 属性判断请求是否成功。如果请求成功,函数将 businessResult 对象作为解析后的 Promise 的值,并调用 resolve(businessResult)。这样,调用这个函数的人就可以通过处理这个 Promise 获取到成功的响应数据。
  • 如果请求失败,代码调用 reject({...}) 来拒绝 Promise,返回一个包含 isBusinessError: truebusinessResult 属性的对象。这样,调用这个函数的人就可以捕获到失败的响应,并处理相应的错误逻辑。
  • 然后,代码检查是否存在状态处理映射对象 shm,并且 shm 中是否定义了针对所有错误的处理函数 shm[ALL_FAIL],或者是否定义了针对特定错误码的处理函数 shm[code]。如果存在这样的处理函数,代码尝试执行它们。这提供了一种灵活的方式来处理特定的错误场景,例如,当服务器返回特定的错误码时,可以执行特定的警告或其他操作。
  • 如果既没有成功也没有 definition 的处理函数,代码将显示一个错误消息,使用 antdalert.error 组件来展示错误信息。
  • 在 Promise 的捕获块 catch((error) => {...}) 中,代码处理 Promise 链中的任何错误。它调用 alertMessage 函数来显示一条服务器异常的错误消息,然后调用 reject({...}) 来拒绝 Promise。这里返回一个包含 isBusinessError: falsemessage: 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 的常量,可能用于表示所有失败情况的错误码。
工具函数
  • alertThenemptyThen:分别用于处理 Promise 链中的成功和失败。alertThen 函数使用 antdalert.error 组件来展示错误信息。emptyThen 函数为空,可能作为默认的成功或失败处理逻辑。
请求方法
  • getpostputfromDatadel:请求方法,它们封装了 axios.getaxios.postaxios.putaxios.delete 方法,用于发起不同类型的 HTTP 请求。这些函数是泛型的,允许指定请求的参数类型 P 和响应类型 R。请求配置对象 Options<R> 允许为每个请求指定特定的状态处理映射对象 shm
请求装饰器
  • decorateRequest:这个函数是一个装饰器,用于装饰请求处理器 RequestHandler<P, R>。装饰器的目的是为请求处理器赋予额外的功能,或者改变它们的行为。在这个特定的装饰器中,它允许为请求处理器提供额外的配置选项。这个装饰器函数实际上创建了一个新的函数,这个新函数被赋予了参数 paramshmrequestConfig。这个新函数内部通过 handler(param, options) 来调用原始请求处理器,并将这三个参数传递给它。这里的 options 对象是通过合并 requestConfigshm 创建的,确保原始请求处理器能够访问这些配置信息。
请求拦截器
  • 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);
  });
相关推荐
拉不动的猪5 分钟前
刷刷题31(vue实际项目问题)
前端·javascript·面试
zeijiershuai7 分钟前
Ajax-入门、axios请求方式、async、await、Vue生命周期
前端·javascript·ajax
恋猫de小郭9 分钟前
Flutter 小技巧之通过 MediaQuery 优化 App 性能
android·前端·flutter
只会写Bug的程序员18 分钟前
面试之《webpack从输入到输出经历了什么》
前端·面试·webpack
拉不动的猪20 分钟前
刷刷题30(vue3常规面试题)
前端·javascript·面试
狂炫一碗大米饭31 分钟前
面试小题:写一个函数实现将输入的数组按指定类型过滤
前端·javascript·面试
最胖的小仙女31 分钟前
通过动态获取后端数据判断输入的值打小
开发语言·前端·javascript
yzhSWJ1 小时前
Vue 3 中,将静态资源(如图片)转换为 URL
前端·javascript·vue.js
Moment1 小时前
🏞 JavaScript 提取 PDF、Word 文档图片,非常简单,别再头大了!💯💯💯
前端·javascript·react.js
听风说雨的人儿1 小时前
ES6 class的继承概念
java·前端·es6