基于axios和react的httpclient封装

2022-04-11  本文已影响0人  Mr无愧于心
import axios from 'axios';
import { message } from 'antd';
import React from 'react';
import stores from '../stores';
/**
 * 支持常用的请求方法包括 ['get', 'delete', 'head', 'post', 'put', 'options']
 * 对外暴露的实例如下
 * 1:HttpClient 满足全局loading样式(需要配合mobx的store管理全局状态)
 * 2:HttpClientOnly 满足不展示对应loading
 * 3:HttpClientPart 满足局部loading(需要配合mobx的store管理全局状态)
*/
axios.defaults.headers['Cache-Control'] = 'no-store,no-cache,no-transform,must-revalidate,max-age=0';
class BaseHttpClient {
  constructor(partName) {
    this.partName = partName;
    this.methods = ['get', 'delete', 'head', 'post', 'put', 'options'];
    this.methods.forEach((item) => {
      this[item] = (url, params = {}, headers = {}) => this.commonMethod(item, url, params, headers)
    })
  }

  baseUrl = '';

  instance = axios.create({
    baseURL: this.baseUrl,
    timeout: 20000,
    withCredentials: true,
  });

  commonMethod (method, url, params = {}, headers) {
    this.url = url
    this.loading && !this.part && stores.gStore.increment();// 增加全局loading状态
    this.loading && this.part && stores.gStore.updateLoadingPart(this.partName, true)// 设置局部loading状态
    let allParams = [url, { params, ...headers = {} }]
    if (['get', 'delete', 'head', 'options'].includes(method)) { // get系请求
      allParams = [url, { params, ...headers }]
    } else if (['post', 'put'].includes(method)) { // post系请求
      allParams = [url, params, headers];
    }
    return this.instance[method](...allParams)
      .then(this.handleSuccessResponse.bind(this))
      .catch(this.handleErrorResponse.bind(this))
      .finally(() => {
        this.loading && !this.part && stores.gStore.reduce();// 减少全局loading()
        this.loading && this.part && stores.gStore.updateLoadingPart(this.partName, false)// 删除局部loading状态
      });
  }

  handleSuccessResponse (res) {// 请求成功}

  handleErrorResponse (err) { //报错处理}
}

function withLoading (loading, part) {
  return (target) => {
    // eslint-disable-next-line no-param-reassign
    target.prototype.loading = loading; // 是否需要loading
    target.prototype.part = part;// 是否需要局部loading
  };
}

// 带有拦截器的HttpClient
class HttpClientWithInterceptors extends BaseHttpClient {
  constructor() {
    super()
    this.instance.interceptors.response.use(
      (response) => response, // 在这里添加响应的拦截
      (error) => {
        const originalRequest = error.config
        if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1 && !originalRequest._retry) {
          message.error('查询超时,请稍后重试')
        }
      },
    );
  }
}

@withLoading(true)
class HttpClientClass extends HttpClientWithInterceptors { }
@withLoading(true, true)
class HttpClientPartClass extends HttpClientWithInterceptors {
  constructor(partName) {
    super();
    this.partName = partName;
  }
}
@withLoading(false)
class HttpClientOnlyClass extends HttpClientWithInterceptors { }

export const HttpClient = new HttpClientClass();
export const HttpClientOnly = new HttpClientOnlyClass();
export const HttpClientPart = (partName) => new HttpClientPartClass(partName);

//---------------------mobx的store------------------------------
// gStore
@observable loadingPart = {}// 存放局部loading的组件标志

@computed get loading() {// 展示全局loading
    return this.httpCount !== 0;
}
@action increment() {
    this.httpCount += 1;
}

@action reduce() {
    this.httpCount -= 1;
 }
@action updateLoadingPart = (partName, loading) => {
    this.loadingPart[partName] = loading;
}
// -----------------------------------
<Spin spinning={stores.gStore.loading}></Spin>// 全局加载
<Spin spinning={stores.gStore.loadingPart.xxx}></Spin>// 局部加载
上一篇下一篇

猜你喜欢

热点阅读