TS对axios 的 数据请求封装

本文详细介绍了如何使用npm或yarn安装axios,定义接口类型,创建axios实例并配置请求和响应拦截器,处理重复请求和超时重试。此外,还展示了如何封装axios基类,提供GET、POST等方法,以及具体业务请求的实现。
摘要由CSDN通过智能技术生成

1. 安装axios

npm i axios --save
yarn add axios --save

2.定义所需要的接口


export type Method = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
export type ResponseType = 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream';

export interface AxiosRequest {
  baseURL?: string;
  url: string;
  data?: any;
  params?: any;
  method?: Method;
  show?: any,
  headers?: any;
  timeout?: number;
  responseType?: ResponseType;
}

export interface AxiosResponse {
  data: any;
  headers: any;
  request?: any;
  status: number;
  statusText: string;
  config: AxiosRequest;
}

export interface CustomResponse {
  readonly status: boolean;
  readonly message: string;
  data: any;
  origin?: any;
}

3.创建axios 实例,并进行拦截器配置

import axios, { AxiosRequestConfig, Method } from 'axios';
import { Toast } from 'vant';

// 定义接口
interface PendingType {
  url?: string;
  method?: Method;
  params: any;
  data: any;
  cancel: Function;
}

// 取消重复请求
const pending: Array<PendingType> = [];
const CancelToken = axios.CancelToken;
// axios 实例
const instance = axios.create({
  timeout: 10000,
  responseType: 'json'
});

// 移除重复请求
const removePending = (config: AxiosRequestConfig) => {
  for (const key in pending) {
    const item: number = +key;
    const list: PendingType = pending[key];
    // 当前请求在数组中存在时执行函数体
    if (list.url === config.url && list.method === config.method && JSON.stringify(list.params) === JSON.stringify(config.params) && JSON.stringify(list.data) === JSON.stringify(config.data)) {
      // 执行取消操作
      list.cancel('操作太频繁,请稍后再试');
      // 从数组中移除记录
      if(pending.length > 1){
        pending.splice(item, 1)
      }
    }
  }
};

// 添加请求拦截器
instance.interceptors.request.use(
  request => {
    Toast({
      message: '加载中',
      forbidClick: true,
    });
    console.log(request,'111')
    removePending(request);
    request.cancelToken = new CancelToken((c) => {
      pending.push({ url: request.url, method: request.method, params: request.params, data:request.data, cancel: c, });
    });
    return request;
  },
  error => {
    return Promise.reject(error);
  }
);

// 添加响应拦截器
instance.interceptors.response.use(
  response => {
    Toast.clear();
    removePending(response.config);
    const errorCode = response?.data?.errorCode;
    switch (errorCode) {
      case '401':
        // 根据errorCode,对业务做异常处理(和后端约定)
        break;
      default:
        break;
    }
    return response;
  },
  error => {
    Toast.clear();
    const response = error.response;
    // 根据返回的http状态码做不同的处理
    switch (response?.status) {
      case 400:
        //  页面找不到
        break;
      case 401:
        // token失效
        break;
      case 403:
        // 没有权限
        break;
      case 500:
        // 服务端错误
        break;
      case 503:
        // 服务端错误
        break;
      default:
        // 接口异常
        break;
    }
    // 超时重新请求
    const config = error.config;
    // 全局的请求次数,请求的间隙
    const [RETRY_COUNT, RETRY_DELAY] = [0, 1000];
    if (config && RETRY_COUNT) {
      // 设置用于跟踪重试计数的变量
      config.__retryCount = config.__retryCount || 0;
      // 检查是否已经把重试的总数用完
      if (config.__retryCount >= RETRY_COUNT) {
        return Promise.reject(response || { message: error.message });
      }
      // 增加重试计数
      config.__retryCount++;
      // 创造新的Promise来处理指数后退
      const backoff = new Promise<void>((resolve) => {
        setTimeout(() => {
          resolve();
        }, RETRY_DELAY || 1);
      });
      // instance重试请求的Promise
      return backoff.then(() => {
        return instance(config);
      });
    }
    return Promise.reject(response || { message: error.message });
  }
);
export default instance;

4.封装axios的基类

/**
 * axios基础构建
 * @date 2021-02-04
 */
import { HOST } from './config';
import instance from './intercept';
import { AxiosRequest, CustomResponse } from './types';
import { Decrypt, Encrypt } from '../until/until';
import { Toast } from 'vant';

 // 外部传入的baseUrl
 const token = window.localStorage.getItem("userInfo")? JSON.parse(Decrypt(window.localStorage.getItem("userInfo"))).token: "",
        reqURL = HOST,
        header: object = {
          'Content-Type': 'application/json;charset=UTF-8',
          'X-Requested-With': 'XMLHttpRequest',
          token: token
        };

class Abstract {
  private apiAxios({ baseURL = reqURL, headers = header, method, url, data, params, responseType, show }: AxiosRequest): Promise<CustomResponse> {
    return new Promise((resolve, reject) => {
      instance({
        baseURL,
        headers,
        method,
        url,
        params,
        data,
        responseType,
      }).then((res) => {
        if (res.headers.token) {
          resetToken(res.headers);
        }
        // 200:服务端业务处理正常结束
        if (res.status === 200) {
          if (res.data.success) {
            resolve({ status: true, message: 'success', data: res.data?.data, origin: res.data });
          } else {
            Toast.fail({ message: res.data?.message });
            resolve({ status: false, message: res.data?.message, data: res.data?.data, origin: res.data });
          }
        } else {
          resolve({ status: false, message: res.data?.message, data: null });
        }
      }).catch((err) => {
        const message = err?.data?.message || err?.message;
        Toast.fail({ message });
        reject({ status: false, message, data: null });
      });
    });
  }

  /**
   * GET类型的网络请求
   */
  protected getRequest({  url, data, params, responseType, show }: AxiosRequest) {
    return this.apiAxios({ method: 'GET', url, data, params, responseType,show });
  }

  /**
   * POST类型的网络请求
   */
  protected postRequest({  url, data, params, responseType, show }: AxiosRequest) {
    return this.apiAxios({ method: 'POST', url, data, params, responseType, show });
  }

  /**
   * PUT类型的网络请求
   */
  protected putRequest({  url, data, params, responseType }: AxiosRequest) {
    return this.apiAxios({ method: 'PUT', url, data, params, responseType });
  }

  /**
   * DELETE类型的网络请求
   */
  protected deleteRequest({  url, data, params, responseType }: AxiosRequest) {
    return this.apiAxios({ method: 'DELETE', url, data, params, responseType });
  }
}

export default Abstract;


function resetToken(header:any) {
  let userInfo = JSON.parse(Decrypt(window.localStorage.getItem("userInfo")));
  delete userInfo["token"];
  userInfo["token"] = header.token;
  window.localStorage.setItem("userInfo", Encrypt(JSON.stringify(userInfo)));
}

5.对访问服务器进行配置

在这里插入图片描述

6.定义具体的业务请求

/**
 * 基础数据 API 集合类
 * 集成Abstract
 * @date 2021-02-03
 */
import Abstract from '../axios/abstract';

class Basic extends Abstract {
    loginCode(params:any) {
        const url = "/shop/h5/open/user/sms/sign/code";
        return new Promise(resolve => {
            this.postRequest({ url, params }).then(res => {
            resolve(res);
            });
        });
    }

    login(params:any) {
        const url = "/shop/h5/open/user/sms/share/sale/login";
        return new Promise(resolve => {
            this.postRequest({ url, params }).then(res => {
            resolve(res);
            });
        });
    }
}
// 单列模式返回对象
let login;
export default (() => {
    if (login) return login;
    login = new Basic();
    return login;
})();

项目文件配置路径
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值