import axios from "axios";
import qs from "qs";

//创建axios的一个实例
var instance = axios.create({
  baseURL: import.meta.env.VITE_BASE_API_URL, //接口统一域名
  timeout: 30000, //设置超时
});

//创建存储 key 的 集合
let keyMap = new Map();

//获取每一次请求的key
function getRequestKey(config) {
  let { url, method, data, params } = config;
  //记得这里一定要处理 每次请求都掉会变化的参数(比如每个请求都携带了时间戳),否则二个请求的key不一样
  let key = [url, method, qs.stringify(data), qs.stringify(params)].join("&");
  return key;
}

//判断是否存在该key,不存在则插入
function checkRequest(config, source) {
  let key = getRequestKey(config);
  if (keyMap.has(key)) {
    source.cancel();
  } else {
    keyMap.set(key, config);
  }
}

//响应完成后,删除key
function deleteRequestKey(config) {
  let key = getRequestKey(config);
  if (keyMap.has(key)) {
    keyMap.delete(key);
  }
}

//请求拦截器
instance.interceptors.request.use(config => {
  //这里 是拦截的关键,使用 axios CancelToken, 每次请求都重新生成 source 和 cancelToken 
  const source = axios.CancelToken.source();
  config.cancelToken = source.token;
  //检查请求
  checkRequest(config, source);
  return config;
});

//响应拦截器
instance.interceptors.response.use(
  result => {
  	// 这里是占位, 第二个是错误处理函数
    return result;
  },
  error => {
    //拦截掉重复请求的错误,中断promise执行
    if (axios.isCancel(error)) {
      return new Promise(() => {});
    }
	
	//不是重复请求错误放行 到 .catch 中
    return Promise.reject(error.response);
  }
);

//封装请求
let request = function (config) {
  //如果你是这里用if处理 config.method 的情况,那么你要注意
  //这里不会像拦截器那样将 config.method 转换成小写, 你需要自己处理
  //config.method = config.method.toLowerCase();
  
  return new Promise(function (resolve, reject) {
    instance(config)
      .then(res => {
      	// 请求成功了但返回没有 data 内容放行到 外层的Promise 的 .catch
        if (res && res.data != "") {
          resolve(res.data);
        } else {
          reject(res);
        }
      })
      .catch(err => {
        reject(err);
      })
      .finally(_ => {
      	// 删除已完成的请求 key
        deleteRequestKey(config);
      });
  });
};

export default request;

代码可以直接使用, 如果要封装 get post 可以以 request 为标准,重新封装, request 并没有做过多处理, 根据自己需求 添加即可, 大致意思已经打上了注释

觉得有用就点个赞吧

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐