如何取消axios的重复请求

如何取消axios的重复请求

    • 什么是axios
    • 取消axios请求
    • 判断重复请求
    • 如何取消重复请求

​ 在 web项目开发的过程中,经常会遇到客服端重复发送请求的场景,如果开发者不对重复的请求进行相应的处理,可能会导致项目崩溃,服务器瘫痪等各种各样的问题出现。通过 axios为例,了解解决重复请求的问题答案。

什么是axios

​ axios是一个基于 Promise的 HTTP客户端,同时支持浏览器和 node.js环境。是一个十分优秀的 HTTP客户端,被广泛运用在大量的 web项目中。

取消axios请求

  1. 浏览器环境:对于浏览器来说,axiso底层是利用 XMLHttpRequest对象来发起 HTTP请求;如果需要取消请求的话,可以通过调用 XMLHttpRequest对象上的 abort方法来取消请求,如下:
let xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.xxx.com",true);
xhr.send();
setTimeout(() => xhr.abort(),300);
  1. 项目内使用 axios的环境:可以通过 axios内部提供的 CancelToken方法来取消请求,具体实现如下:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.post('/api/user', {
    name:'admin'
}, {
    cancelToken: source.token
})

source.cancel('取消请求'); // 取消请求,参数可选

​ 此外,也可以通过调用 CancelToken的构造函数来创建 CancelToKen,如下:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/api/user', {
	cancelToken: new CancelToken(function excutor(c){
        cancel = c;
    })
});

cancel(); // 取消请求

判断重复请求

​ 当请求方式,请求 URL和请求携带参数都一样时,就可以认为是相同的请求。因此在每次发起请求时,可以根据当前请求的请求方式、请求 URL地址和请求携带参数来生成一个唯一的 key;同时为每个请求创建一个专属的 CancelToken,然后将 key 和 Cancel 函数以键值对的形式保存到 Map对象中,使用 Map对象的好处是可以快速判断是否有重复的请求,具体实现如下:

import qs from "qs"

const pendingRequest = new Map();
// GET --> params, POST --> data
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&');
const cancelToken = new CancelToken(function excutor(cancel){
    if(!pendingRequest.has(requestKey)){
        pendingRequest.set(requestKey,cancel)
    }
})

出现重复请求时,就可以调用 cancel函数来取消之前已经发出的请求。在取消请求之后,还需要把取消的请求从 pendingRequest中移除。

如何取消重复请求

因为需要对所有的请求都进行处理,所以可以考虑使用 axios的拦截器机制来实现取消重复请求的功能。

axios的制作者为开发人员提供了请求拦截器和响应拦截器,各自的作用如下:

  1. 请求拦截器:该类拦截器的作用是在请求发送前统一执行某些操作,比如在请求头中添加 token字段;
  2. 响应拦截器:该类拦截器的作用是在接收到服务器响应后统一执行某些操作,比如根据不同的状态码来执行相对应的操作。

在配置请求拦截器和响应拦截器之前,需要先定义三个辅助函数:

  1. generateReqKey,用于根据当前请求的信息生成请求的 Key
function generateReqKey(config){
    const {method, url, params, data } = config;
    return [method, url, qs.stringify(params), qs.stringify(data)].join('&')
}
  1. 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)
        }
    });
}
  1. removePendingRequest,检查是否存在重复请求,若存在则需要取消已发出的请求
function removePendingRequest(config){
    const requestKey = generateReqKey(config);
    if(pendingRequest.has(requestKey)){
       const cancelToken = pendingRequest.get(requestKey);
       cancelToken(requestKey);
       pendingRequest.delete(requestKey);
    }
}

创建好这三个函数以后,就可以设置请求拦截器和响应拦截器

  1. 请求拦截器
axios.interceptors.request.use(
    function (config) {
        removePendingRequest(config); // 检查是否存在重复请求
        addPendingRequest(config); // 将当前请求信息添加到 pendingRequest对象中
        return config;
    },
    (error) => {
        return Promise.reject(error);
    }
);
  1. 响应拦截器
axios.interceptors.response.use(
     (response) => {
        removePendingRequest(response.config); // 从 pendingRequest对象中移除请求
         return response;
    },
    (error) => {
        removePendingRequest(error.config || {}); // 从 pendingRequest对象中移除请求
        if(axios.isCancel(error)){
            console.log(error.message);
        }else {
            // 自行处理异常请求
        }
        return Promise.reject(error);
    }
);

这里是万物之恋,我们下次再见了!

你可能感兴趣的:(前端面试题,前端,javascript,vue.js)