基于axios的请求loading封装

115 阅读1分钟

axios二次封装

因为项目中很多时候需要发起请求的时候有loading效果,避免看起来操作卡顿,或者点击的时候没有任何反馈给用户,所以就想着在发起请求的时候做个全局的loading,这个放在请求拦截封装里是最合适的,业务不需要关心怎么实现,只要配置即可

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
import { message as Message, Spin } from "antd";
import ReactDOM from "react-dom";

interface IAxiosResponse extends AxiosResponse { 
  config: InternalAxiosRequestConfig & { loading?: boolean }
}

const createLoadingDOM = () => {
  const dom = document.createElement('div')
  dom.setAttribute('id', 'loading')
  document.body.appendChild(dom)
  ReactDOM.render(<Spin />, dom)
}

const removeLoadingDOM = () => { 
  const dom = document.getElementById('loading') as HTMLDivElement;
  document.body.removeChild(dom!);
}

let requestNum = 0;

const addLoading = () => {
  // 增加loading 如果pending请求数量等于1,弹出loading, 防止重复弹出
  requestNum++;
  if (requestNum == 1) {
    createLoadingDOM();
  }
};

const cancelLoading = () => {
  // 取消loading 如果pending请求数量等于0,关闭loading
  requestNum--;
  if (requestNum === 0) {
    removeLoadingDOM();
  };
};

export const createAxiosByInterceptors = (
  config?: AxiosRequestConfig
): AxiosInstance => {
  const instance = axios.create({
    timeout: 60000,    //超时配置
    withCredentials: true,  //跨域携带cookie
    ...config,   // 自定义配置覆盖基本配置
  });

  // 添加请求拦截器
  instance.interceptors.request.use(
    function (config: any) {
      // 在发送请求之前做些什么
      const { loading = true } = config;
      let regex = /.+?ccsrf=(.+?)\;.*/
      config.headers['Hcsrf'] = document.cookie.match(regex)![1];
      if (loading) addLoading();
      return config;
    },
    function (error) {
      // 对请求错误做些什么
      return Promise.reject(error);
    }
  );

  // 添加响应拦截器
  instance.interceptors.response.use(
    function (response: IAxiosResponse) {
      // 对响应数据做点什么
      console.log("response:", response);
      const { loading = true } = response.config;
      if (loading) cancelLoading();
      const { code, data, message } = response.data;
      // config设置responseType为blob 处理文件下载
      if (response.data instanceof Blob) {
        // TODO: 文件下载
        // return downloadFile(response);
      } else {
        if (code === '000000') return data;
        else if (code === 'AUTH_EXPIRE') {
          // jumpLogin();
          // TODO: 跳转登录
        } else {
          Message.error(message);
          return Promise.reject(response.data);
        }
      }
    },
    function (error) {
      const { loading = true } = error?.config || {};
      if (loading) cancelLoading();
      if (error.response) {
        if (error.response.status === 401) {
          // TODO: 跳转登录
          // jumpLogin();
        }
      }
      Message.error(error?.response?.data?.message || "服务端异常");
      return Promise.reject(error);
    }
  );
  return instance;
};


const request = createAxiosByInterceptors();

export default request;