axios 取消重复请求

本文介绍了如何在使用Axios进行项目开发时,通过生成请求Key并监控pendingRequest对象,实现对重复请求的自动取消,以减轻服务器压力。详细讲解了generateReqKey函数、addPendingRequest和removePendingRequest的实现以及在axios封装中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在项目当中,一般请求接口我们会用axios进行统一处理,有时候在页面当中会遇到多次请求同一个接口。如果我们在第2次请求同一个接口时,第一次发送的接口请求还没有得到服务器的响应时,就可以把第一次的接口请求取消掉,这样可以减轻http服务的请求压力。

那么,我们怎么判断2次请求是否相同呢?一般当2个请求的接口地址,请求方式,请求参数都一致时,我们就认为这2个请求相同。因此,我们可以使用一个函数来根据请求信息,生成一个key

generateReqKey:用于根据当前请求的信息,生成请求 Key;

// generateReqKey:用于根据当前请求的信息,生成请求 Key;
function generateReqKey(config) {
    const { method, url, params, data } = config;
    return [method, url, qs.stringify(params), qs.stringify(data)].join("&");
}

addPendingRequest:用于把当前请求信息添加到pendingRequest对象中;

// addPendingRequest:用于把当前请求信息添加到pendingRequest对象中;
const pendingRequest = new Map();
function addPendingRequest(config) {
  const requestKey = generateReqKey(config);
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingRequest.has(requestKey)) {
       pendingRequest.set(requestKey, cancel);
    }
  });
}

removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。

// removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
function removePendingRequest(config) {
  const requestKey = generateReqKey(config);
  if (pendingRequest.has(requestKey)) {
      const cancelToken = pendingRequest.get(requestKey);
      cancelToken(requestKey);
      pendingRequest.delete(requestKey);
  }
}

具体在axios的封装中的使用方法:

import {addPendingRequest,removePendingRequest} from '@/util/http'; // 引入添加请求和取消请求

在http request拦截中

//http request拦截
axios.interceptors.request.use(config => {
  removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
  addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中

  return config
}, error => {
  return Promise.reject(error)
});

在http response 拦截中

//http response 拦截
axios.interceptors.response.use(res => {
  removePendingRequest(res.config); // 从pendingRequest对象中移除请求
  return res;
}, error => {
  NProgress.done();
  removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
  if (axios.isCancel(error)) {
    console.log("已取消的重复请求:" + error.message);
  } else {
    // 添加异常处理
    console.log(error)
  }

  return Promise.reject(new Error(error));
});

完整的代码如下:

1、先单独写个http.js文件,用来写generateReqKey,addPendingRequest,removePendingRequest 三个函数

http.js

import axios from 'axios';
import qs from 'qs'

// generateReqKey:用于根据当前请求的信息,生成请求 Key;
function generateReqKey(config) {
    const { method, url, params, data } = config;
    return [method, url, qs.stringify(params), qs.stringify(data)].join("&");
}

// addPendingRequest:用于把当前请求信息添加到pendingRequest对象中;
const pendingRequest = new Map();
function addPendingRequest(config) {
  const requestKey = generateReqKey(config);
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingRequest.has(requestKey)) {
       pendingRequest.set(requestKey, cancel);
    }
  });
}

// removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求。
function removePendingRequest(config) {
  const requestKey = generateReqKey(config);
  if (pendingRequest.has(requestKey)) {
      const cancelToken = pendingRequest.get(requestKey);
      cancelToken(requestKey);
      pendingRequest.delete(requestKey);
  }
}


export {
    addPendingRequest,
    removePendingRequest,
}

2、在封装的axios.js文件中使用

axios.js

/**
 * 全站http配置
 *
 * axios参数说明
 * isSerialize是否开启form表单提交
 * isToken是否需要token
 */
import axios from 'axios';
import store from '@/store/';
import router from '@/router/router';
import {serialize} from '@/util/util';
import {getToken,getDsToken} from '@/util/auth';
import {Message} from 'element-ui';
import website from '@/config/website';
import {Base64} from 'js-base64';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import {addPendingRequest,removePendingRequest} from '@/util/http'; // 引入添加请求和取消请求

//默认超时时间
axios.defaults.timeout = 60000;
//返回其他状态码
axios.defaults.validateStatus = function (status) {
  return status >= 200 && status <= 500;
};
//跨域请求,允许保存cookie
axios.defaults.withCredentials = false;
// NProgress 配置
NProgress.configure({
  showSpinner: false
});
//http request拦截
axios.interceptors.request.use(config => {
  //开启 progress bar
  !config.noNProgress && NProgress.start();
  const meta = (config.meta || {});
  const isToken = meta.isToken === false;
  config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
  //让每个请求携带token
  if (getToken() && !isToken) {
    config.headers[website.tokenHeader] = 'bearer ' + getToken()
  }
  config.headers.token = getDsToken();
  config.headers.language = 'ZH_CN'
  //headers中配置text请求
  if (config.text === true) {
    config.headers["Content-Type"] = "text/plain";
  }
  //headers中配置serialize为true开启序列化
  if ((config.method === 'post'||config.method === 'put') && meta.isSerialize === true) {
    config.data = serialize(config.data);
  }
  axios.defaults.timeout = config.timeout || 20000

  removePendingRequest(config); // 检查是否存在重复请求,若存在则取消已发的请求
  addPendingRequest(config); // 把当前请求信息添加到pendingRequest对象中

  return config
}, error => {
  return Promise.reject(error)
});
//http response 拦截
axios.interceptors.response.use(res => {
  //关闭 progress bar
  NProgress.done();
  //获取状态码
  const status = res.data.code || res.status;
  const statusWhiteList = website.statusWhiteList || [];
  const message = res.data.msg || res.data.error_description || '未知错误';
  //如果在白名单里则自行catch逻辑处理
  if (statusWhiteList.includes(status)) return Promise.reject(res);
  //如果是401则跳转到登录页面
  if (status === 401)store.dispatch('FedLogOut').then(() => router.push({path: '/login'}));
  // 如果请求为非200否者默认统一处理
  if (status !== 200&&status!== 201) {
    // 处理特殊的响应返回
    if(res.config.responseType=="blob"){
      const reader = new FileReader()
      reader.readAsText(res.data)
      reader.onload = e => {
        const { msg } = JSON.parse(reader.result)
        this.$message.error(msg)
      }
      return res
    }
    Message({
      message: message,
      type: 'error'
    });
    return Promise.reject(new Error(message))
  }
  removePendingRequest(res.config); // 从pendingRequest对象中移除请求
  return res;
}, error => {
  NProgress.done();
  removePendingRequest(error.config || {}); // 从pendingRequest对象中移除请求
  if (axios.isCancel(error)) {
    console.log("已取消的重复请求:" + error.message);
  } else {
    // 添加异常处理
    console.log(error)
  }

  return Promise.reject(new Error(error));
});

export default axios;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值