Typescript 封装 axios

233 阅读1分钟
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { Message } from '@arco-design/web-react';
import history from '../history';
import { HEADER_CLIENT_VALUE, HEADER_CLIENT, HEADER_TOKEN } from './constants';

const DEFAULT_LOADING = false;

export interface ApiResult<T> {
  code: number;
  success: boolean;
  msg: string;
  result?: T;
}

export interface RequestConfig extends AxiosRequestConfig {
  loading?: boolean;
}

const interceptors = {
  requestSuccess: (config) => {
    const token = localStorage.getItem(HEADER_TOKEN);
    if (token) {
      config.headers[HEADER_TOKEN] = token;
    }
    config.headers[HEADER_CLIENT] = HEADER_CLIENT_VALUE;
    return config;
  },
  requestError: (error) => {
    return Promise.reject(error);
  },
  responseSuccess: (res) => {
    const { code, msg } = res.data;
    if (code === -1) {
      Message.error(msg || '抱歉,请求异常.');
    }
    return res;
  },
  responseError: (error) => {
    const { message, response } = error;
    console.error('responseError: ', message);
    if (response) {
      const { status, data } = response;
      switch (status) {
        case 401:
          Message.error('用户没有访问权限,需要进行身份认证');
          localStorage.setItem('userStatus', 'logout');
          localStorage.removeItem(HEADER_TOKEN);
          history.push('/user/login');
          break;
        case 403:
          Message.error('对不起,您没有访问该资源的权限.');
          break;
        case 404:
          Message.error('抱歉,页面不见了~');
          break;
        case 500:
          Message.error('抱歉,系统异常~');
          break;
        default:
          Message.error(data.msg || '抱歉,请求失败.');
      }
    }
    return Promise.reject(error);
  },
};

class Request {
  public instance: AxiosInstance;

  public loading: boolean;

  // public loadingInstance?: ILoadingInstance;

  constructor(config: RequestConfig) {
    this.loading = config.loading ?? DEFAULT_LOADING;
    this.instance = axios.create(config);
    this.instance.interceptors.request.use(interceptors.requestSuccess, interceptors.requestError);
    this.instance.interceptors.response.use(
      interceptors.responseSuccess,
      interceptors.responseError
    );
  }

  // 传入的泛型是约束返回值
  request<T>(config: RequestConfig): Promise<ApiResult<T>> {
    return new Promise((resolve, reject) => {
      // 定制该请求是否加loading。当为传入该参数时,默认为true
      if (config.loading === false) {
        this.loading = false;
      }
      this.instance
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        .request<any, AxiosResponse>(config)
        .then((res) => resolve(res.data))
        .catch((err) => reject(err));
    });
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  get<T>(url: string, params?: any, config?: RequestConfig): Promise<ApiResult<T>> {
    return this.request<T>({ ...config, url, params, method: 'GET' });
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  delete<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResult<T>> {
    return this.request<T>({ ...config, url, data, method: 'DELETE' });
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  post<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResult<T>> {
    return this.request<T>({ ...config, url, data, method: 'POST' });
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  put<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResult<T>> {
    return this.request<T>({ ...config, url, data, method: 'PUT' });
  }
}

const request = new Request({
  baseURL: '/api',
  loading: true,
  timeout: 60000,
});

export default request;