如何用ts搭建一个vue3通用项目底座 | 第六篇:axios封装

前言

本篇来封装一个axios,这部分很重要。

1、createAxios函数

新建/@/utils/http/index.ts文件,这里面用来存放核心的createAxios函数。

// /@/utils/http/index.ts
function createAxios(opt?: Partial<CreateAxiosOptions>) {
   
  return new VAxios(
    // 深度合并
    deepMerge(
      {
   
        // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
        // authentication schemes,e.g: Bearer
        // authenticationScheme: 'Bearer',
        authenticationScheme: '',
        timeout: 10 * 1000,
        // 基础接口地址
        // baseURL: globSetting.apiUrl,

        headers: {
    'Content-Type': ContentTypeEnum.JSON },
        // 如果是form-data格式
        // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
        // 数据处理方式
        transform: clone(transform),
        // 配置项,下面的选项都可以在独立的接口请求中覆盖
        requestOptions: {
   
          // 默认将prefix 添加到url
          joinPrefix: true,
          // 是否返回原生响应头 比如:需要获取响应头时使用该属性
          isReturnNativeResponse: false,
          // 需要对返回数据进行处理
          isTransformResponse: true,
          // post请求的时候添加参数到url
          joinParamsToUrl: false,
          // 格式化提交参数时间
          formatDate: true,
          // 消息提示类型
          errorMessageMode: 'message',
          // 接口地址
          apiUrl: globSetting.apiUrl,
          // 接口拼接地址
          urlPrefix: urlPrefix,
          //  是否加入时间戳
          joinTime: true,
          // 忽略重复请求
          ignoreCancelToken: true,
          // 是否携带token
          withToken: true,
          retryRequest: {
   
            isOpenRetry: true,
            count: 5,
            waitTime: 100,
          },
        },
      },
      opt || {
   },
    ),
  );
}
export const defHttp = createAxios();

有很多爆红,下面逐个解析。

1.1、CreateAxiosOptions类型

新建/@/utils/http/axios/axiosTransform.ts文件作为数据处理类。

// /@/utils/http/axios/axiosTransform.ts
/**
 * 数据处理类,可根据项目配置
 */
import type {
    AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import type {
    RequestOptions, Result } from '/#/axios';

export interface CreateAxiosOptions extends AxiosRequestConfig {
   
  authenticationScheme?: string;
  transform?: AxiosTransform;
  requestOptions?: RequestOptions;
}

export abstract class AxiosTransform {
   
  /**
   * @description: 请求前的流程配置
   */
  beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig;

  /**
   * @description: 处理响应数据
   */
  transformResponseHook?: (res: AxiosResponse<Result>, options: RequestOptions) => any;

  /**
   * @description: 请求失败处理
   */
  requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>;

  /**
   * @description: 请求之前的拦截器
   */
  requestInterceptors?: (
    config: InternalAxiosRequestConfig,
    options: CreateAxiosOptions,
  ) => InternalAxiosRequestConfig;

  /**
   * @description: 请求之后的拦截器
   */
  responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>;

  /**
   * @description: 请求之前的拦截器错误处理
   */
  requestInterceptorsCatch?: (error: Error) => void;

  /**
   * @description: 请求之后的拦截器错误处理
   */
  responseInterceptorsCatch?: (axiosInstance: AxiosResponse, error: Error) => void;
}

从axiosTransform数据处理类里面可以看到后续要封装的各种函数处理。
接着去全局类型里补充缺失的类型,新建/@/types/axios.d.ts文件。

// /@/types/axios.d.ts
export type ErrorMessageMode = 'none' | 'modal' | 'message' | undefined;
export type SuccessMessageMode = ErrorMessageMode;

export interface RequestOptions {
   
  // 将请求参数拼接到url
  joinParamsToUrl?: boolean;
  // 格式化请求参数时间
  formatDate?: boolean;
  // 是否处理请求结果
  isTransformResponse?: boolean;
  // 是否返回本机响应标头
  // 例如:当您需要获取响应标头时,请使用此属性
  isReturnNativeResponse?: boolean;
  // 是否加入url
  joinPrefix?: boolean;
  // 接口地址,如果保留为空,请使用默认的apiUrl
  apiUrl?: string;
  // 请求拼接路径
  urlPrefix?: string;
  // 错误消息提示类型
  errorMessageMode?: ErrorMessageMode;
  // 成功消息提示类型
  successMessageMode?: SuccessMessageMode;
  // 是否添加时间戳
  joinTime?: boolean;
  ignoreCancelToken?: boolean;
  // 是否在标头中发送token
  withToken?: boolean;
  // 请求重试机制
  retryRequest?: RetryRequest;
}

export interface RetryRequest {
   
  isOpenRetry: boolean;
  count: number;
  waitTime: number;
}
export interface Result<T = any> {
   
  code: number;
  type: 'success' | 'error' | 'warning';
  message: string;
  result: T;
}

// multipart/form-data: upload file
// 文件上传
export interface UploadFileParams {
   
  // 其他参数
  data?: Recordable;
  // 文件参数接口字段名称
  name?: string;
  // 文件名
  file: File | Blob;
  // 文件名
  filename?: string;
  [key: string]: any;
}

import { CreateAxiosOptions } from ‘./axios/axiosTransform’;
这样CreateAxiosOptions类型就ok了。

1.2、VAxios类

新建/@/utils/http/axios/index.ts文件作为axios模块类。

// /@/utils/http/axios/index.ts
import type {
   
  AxiosRequestConfig,
  InternalAxiosRequestConfig,
  AxiosInstance,
  AxiosResponse,
  AxiosError,
} from 'axios';
import type {
    RequestOptions, Result, UploadFileParams } from '/#/axios';
import type {
    CreateAxiosOptions } from './axiosTransform';
import axios from 'axios';
import qs from 'qs';
import {
    AxiosCanceler } from './axiosCancel';
import {
    isFn } from '/@/utils/is';
import {
    cloneDeep } from 'lodash-es';
import {
    ContentTypeEnum } from '/@/enums/httpEnum';
import {
    RequestEnum } from '/@/enums/httpEnum';

export * from './axiosTransform';

/**
 * @description:  axios模块
 */
export class VAxios {
   
  private axiosInstance: AxiosInstance;
  private readonly options: CreateAxiosOptions;

  constructor(options: CreateAxiosOptions) {
   
    this.options = options;
    this.axiosInstance = axios.create(options);
    this.setupInterceptors();
  }

  /**
   * @description:  创建axios实例
   */
  private createAxios(config: CreateAxiosOptions): void {
   
    this.axiosInstance = axios.create(config);
  }

  private getTransform() {
   
    const {
    transform } = this.options;
    return transform;
  }

  getAxios(): AxiosInstance {
   
    return this.axiosInstance;
  }

  /**
   * @description: 重新配置axios
   */
  configAxios(config: CreateAxiosOptions) {
   
    if (!this.axiosInstance) {
   
      return;
    }
    this.createAxios(config);
  }

  /**
   * @description: 设置通用header
   */
  setHeader(headers: any): void {
   
    if (!this.axiosInstance) {
   
      return;
    }
    Object.assign(this.axiosInstance.defaults.headers, headers);
  }

  /**
   * @description: 拦截器配置
   */
  private setupInterceptors() {
   
    const transform = this.getTransform();
    if (!transform) {
   
      return;
    }
    const {
   
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform;

    const axiosCanceler = new AxiosCanceler();

    // 请求拦截器配置处理
    this.axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
   
      // 如果取消重复请求已打开,则禁止取消重复请求
      // @ts-ignore
      const {
    ignoreCancelToken } = config.requestOptions;
      const ignoreCancel =
        ignoreCancelToken !== undefined
          ? ignoreCancelToken
          : this.options.requestOptions?.ignoreCancelToken;

      !ignoreCancel && axiosCanceler.addPending(config);
      if (requestInterceptors && isFn(requestInterceptors)) {
   
        config = requestInterceptors(config, this.options);
      }
      return config;
    }, undefined);

    // 请求拦截器错误捕获
    requestInterceptorsCatch &&
      isFn(requestInterceptorsCatch) &&
      this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);

    // 响应结果拦截器处理
    this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
   
      res && axiosCanceler.removePending(res.config);
      if (responseInterceptors && isFn(responseInterceptors)) {
   
        res = responseInterceptors(res);
      }
      return res;
    }, undefined);

    // 响应结果拦截器错误捕获
    responseInterceptorsCatch &&
      isFn(responseInterceptorsCatch) &&
      this.axiosInstance.interceptors.response.use(undefined, (error
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值