Axios 之 ts 版本的请求封装

1、安装

npm install axios

文档链接:中文文档

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;

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;

取消请求的封装:
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}`;
}

全局加载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;

src/enums/httpEnum.ts

/**
 * @description:响应结果枚举
 */
 export enum ResponseCodeEnum {
	SUCCESS = 200,
	ERROR = 500,
	NOLOGIN = 499,
}

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

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

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

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
对于 TypeScript 中的 Axios 请求封装,你可以创建一个单独的文件或者模块来处理这个逻辑。以下是一个简单的示例: ```typescript import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; // 创建一个自定义的请求实例 const instance = axios.create({ baseURL: 'https://api.example.com', timeout: 5000, // 请求超时时间 }); // 定义请求拦截器 instance.interceptors.request.use( (config: AxiosRequestConfig) => { // 可以在这里做一些请求前的处理,比如添加请求头等 return config; }, (error: any) => { // 错误处理 return Promise.reject(error); } ); // 定义响应拦截器 instance.interceptors.response.use( (response: AxiosResponse) => { // 可以在这里对响应数据做一些处理,比如统一处理错误码等 return response; }, (error: any) => { // 错误处理 return Promise.reject(error); } ); // 封装 GET 请求 export const get = <T>(url: string, params?: any): Promise<T> => { return instance.get<T>(url, { params }); }; // 封装 POST 请求 export const post = <T>(url: string, data?: any): Promise<T> => { return instance.post<T>(url, data); }; // 封装其他请求方式,比如 PUT、DELETE 等 ``` 使用时,可以在其他文件中导入封装好的请求方法,并发起请求,例如: ```typescript import { get, post } from './api'; // 发起 GET 请求 get<User[]>('/users') .then(response => { const users = response.data; // 处理响应数据 }) .catch(error => { // 处理错误 }); // 发起 POST 请求 const data = { username: 'example', password: 'password' }; post('/login', data) .then(response => { // 处理响应数据 }) .catch(error => { // 处理错误 }); ``` 这只是一个简单的示例,你可以根据自己的项目需求进行更加复杂的封装,比如添加请求取消、错误提示等功能。希望对你有所帮助!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值