当前位置:   article > 正文

Axios 之 ts 版本的请求封装_axios ts

axios ts

1、安装

npm install axios
  • 1

文档链接:中文文档

2、常用封装

2.1 简单版本的封装

这里仅封装常用的 get、post、put、delete 几种方法
且只封装几种常见的报错提示
src/utils/request.ts

import axios, {
  AxiosError,
  AxiosInstance,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from "axios";

const config = {
  baseURL: "http://localhost:3000/api",
  timeout: 10000,
  withCredentials: true,
  headers: {},
};

class RequestHttp {
  service: AxiosInstance;

  constructor() {
    this.service = axios.create(config);

    /**
     * @description 请求拦截器
     */
    this.service.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        return config;
      }
    );

    /**
     * @description 响应拦截器
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        const { data } = response;
        return data;
      },

      (error: AxiosError) => {
        const { response } = error;
        if (response) {
          checkStatus(response.status);
        }
        return false;
      }
    );
  }

  // 常用请求方法封装
  get(url: string, params?: object, _object = {}) {
    return this.service.get(url, { params, ..._object });
  }
  post(url: string, params?: object, _object = {}) {
    return this.service.post(url, params, _object);
  }
  put(url: string, params?: object, _object = {}) {
    return this.service.put(url, params, _object);
  }
  delete(url: string, params?: any, _object = {}) {
    return this.service.delete(url, { params, ..._object });
  }
}

/**
 * @description: 校验网络请求状态码
 * @param {Number} status
 * @return void
 */
 const checkStatus = (status: number): void => {
  switch (status) {
      case 404:
          console.warn("资源不存在!");
          break;
      case 405:
          console.warn("请求方式错误!");
          break;
      case 500:
          console.warn("服务器异常!");
          break;
      default:
          console.warn("请求失败!");
  }
};

const request = new RequestHttp();
export default request;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

2.1 包含多处理的封装

增加如下处理

  1. 请求loading
  2. 取消请求(CancelToken)
  3. 请求结果的更细节处理

src/utils/request.ts

import { message } from "antd";
import axios, {
  AxiosInstance,
  InternalAxiosRequestConfig,
  AxiosResponse,
  AxiosError,
} from "axios";
import { store } from "@/redux";
import { ResponseCodeEnum } from "@/enums/httpEnum";
import { setToken } from "@/redux/modules/global";
import { ResultData } from "@/api/types/index.type";
import fullLoading from "./fullLoading";
import { AxiosCancel } from "./AxiosCancel";

const config = {
  baseURL: "http://localhost:3000/api",
  timeout: 5000,
  withCredentials: true,
  headers: {},
};

const axiosCancel = new AxiosCancel();

class RequestHttp {
  service: AxiosInstance;

  constructor() {
    this.service = axios.create(config);

    /**
     * @description 请求拦截器
     */
    this.service.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        console.log(config)

        // 打开全局 loading
        // 如不需要全局 loading,则第三个参数  { headers: { noLoading: true } }
        if(!config.headers.noLoading) {
          fullLoading.show();
        }

        // 将请求添加到 pending 中
        axiosCancel.addPending(config);

        // 这里如果需要添加token
        const token = store.getState().global.token; // 我这里用的是 react-redux + redux-toolkit
        config.headers["X-Access-Token"] = token;

        return config;
      }
    );

    /**
     * @description 响应拦截器
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        const { data, config } = response;

        // 关闭全局 loading
        if(!config.headers.noLoading) {
          fullLoading.hide();
        }

        // 请求结束,移除本次请求
        axiosCancel.removePending(config.url, config.method);

        // 接口返回 code 不是 200 的处理
        if (data.code !== ResponseCodeEnum.SUCCESS) {
          message.error(data.msg);

          // 登录失效,清除 token,跳转到登录页面
          if (data.code === ResponseCodeEnum.NOLOGIN) {
            store.dispatch(setToken(""));
            window.location.href = "/login";
          }

          return Promise.reject(data);
        }
        return data;
      },

      (error: AxiosError) => {
        fullLoading.hide();

        const { response } = error;
        if (response) {
          checkStatus(response.status);
        }
        return false;
      }
    );
  }

  // 常用请求方法封装
  get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
    return this.service.get(url, { params, ..._object });
  }
  post<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
    return this.service.post(url, params, _object);
  }
  put<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
    return this.service.put(url, params, _object);
  }
  delete<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
    return this.service.delete(url, { params, ..._object });
  }
}

/**
 * @description: 校验网络请求状态码
 * @param {Number} status
 * @return void
 */
const checkStatus = (status: number): void => {
  switch (status) {
    case 404:
      message.error("资源不存在!");
      break;
    case 405:
      message.error("请求方式错误!");
      break;
    case 500:
      message.error("服务器异常!");
      break;
    default:
      message.error("请求失败!");
  }
};

const request = new RequestHttp();
export default request;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

取消请求的封装:
src/utils/AxiosCancel.ts

import axios, { AxiosRequestConfig, Canceler } from "axios";

const cancelMap = new Map<string, Canceler>();

export class AxiosCancel {
  /**
   * 添加请求的 cancel
   * @param config
   */
  addPending(config: AxiosRequestConfig) {
    const { url, method } = config;

    if (!url || !method) return;

    // 处理同个api,同时多次请求的情况,先移除上一个
    this.removePending(url, method);

    const key = getCancelMapKey(url, method);
    config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
      if (!cancelMap.has(key)) {
        cancelMap.set(key, cancel);
      }
    });
  }

  /**
   * 移除请求
   * @param url
   * @param method
   */
  removePending(url: string | undefined, method: string | undefined) {
    if (!url || !method) return;    

    const key = getCancelMapKey(url, method);
    const cancel = cancelMap.get(key);
    if (cancel) {
      cancel();
      cancelMap.delete(key);
    }
  }

  /**
   * 移除所有请求
   */
  removeAllPending() {
    cancelMap.forEach((cancel) => {
      cancel && cancel();
    });
    cancelMap.clear();
  }
}

function getCancelMapKey(url: string, method: string) {
  return `${url}_${method}`;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

全局加载loading
src/utils/fullLoading.ts

import ReactDOM from "react-dom/client";
import { Spin } from "antd";

// 当前请求的个数
let reqCount = 0;

// 显示 loading
function show() {
  if (reqCount === 0) {
    const dom = document.createElement("div");
    dom.id = "loading";
    dom.style.position = "fixed";
    dom.style.top = "0";
    dom.style.right = "0";
    dom.style.bottom = "0";
    dom.style.left = "0";
    dom.style.background = "rgba(0, 0, 0, 0.5)";
    dom.style.display = "flex";
    dom.style.justifyContent = "center";
    dom.style.alignItems = "center";
    dom.style.zIndex = "9999";
    document.body.appendChild(dom);
    ReactDOM.createRoot(dom).render(<Spin size="large"></Spin>);
  }
  reqCount++;
}

// 隐藏 loading
function hide() {
  reqCount--;
  if (reqCount === 0) {
    const dom = document.getElementById("loading");
    if (dom) {
      document.body.removeChild(dom as HTMLElement);
    }
  }
}

const fullLoading = {
  show,
  hide,
};

export default fullLoading;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

src/enums/httpEnum.ts

/**
 * @description:响应结果枚举
 */
 export enum ResponseCodeEnum {
	SUCCESS = 200,
	ERROR = 500,
	NOLOGIN = 499,
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

类型文件
src/api/type/api.type.ts

// 接口返回结构,不包含 data
export interface ResponseResult {
  // 状态码
  code: number;
  // 消息
  msg: string;
}

// 完整的接口返回结构
export interface ResultData<T = any> extends ResponseResult {
  // 数据
  data: T;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号