首页 > 其他分享 >axios中取消请求及阻止重复请求的方法

axios中取消请求及阻止重复请求的方法

时间:2023-02-17 17:00:39浏览次数:41  
标签:axios 请求 url 阻止 reqList cancel CancelToken

前言

在实际项目中,我们可能需要对请求进行“防抖”处理。这里主要是为了阻止用户在某些情况下短时间内重复点击某个按钮,导致前端向后端重复发送多次请求。这里我列举两种比较常见的实际情况:

  • PC端 - 用户双击搜索按钮,可能会触发两次搜索请求
  • 移动端 - 因移动端没有点击延迟,所以极易造成误操作或多操作,造成请求重发

以上情况有可能在有Loading遮罩时依然发生,所以我们要考虑前端阻止重复请求的方法。

核心——CancelToken

在Axios中取消请求最核心的方法是CanelToken。在官网文档中有写到两种方法使用CancelToken,这里简单粘贴出来,并增加了注释

方法1:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();
 
axios.get('/user/12345', {
  // 必须对请求进行cancelToken设置
  cancelToken: source.token
}).catch(function (thrown) {
  // 如果请求被取消则进入该方法判断
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});
 
// 取消上面的请求
// source.cancel('messge') message为可选项,必须为String
source.cancel('Operation canceled by the user.');

方法2:

const CancelToken = axios.CancelToken;
let cancel;
 
axios.get('/user/12345', {
  // 在options中直接创建一个cancelToken对象
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});
 
// 取消上面的请求
cancel();

实际应用和封装

上文已对axios中的核心方法进行了举例,但是在实际中我们往往不会像官网例子中那样使用,更多的是在axios的拦截器中做全局配置管理。这样的话我们需要对上面的代码进行一些改变。

这里说一下我实现的大体思路:

  • 我们需要对所有正在进行中的请求进行缓存。在请求发起前判断缓存列表中该请求是否正在进行,如果有则取消本次请求。
  • 在任意请求完成后,需要在缓存列表中删除该次请求,以便可以重新发送该请求
    思路说完,我们直接上代码
// 正在进行中的请求列表
let reqList = []
 
/**
 * 阻止重复请求
 * @param {array} reqList - 请求缓存列表
 * @param {string} url - 当前请求地址
 * @param {function} cancel - 请求中断函数
 * @param {string} errorMessage - 请求中断时需要显示的错误信息
 */
const stopRepeatRequest = function (reqList, url, cancel, errorMessage) {
  const errorMsg = errorMessage || ''
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      cancel(errorMsg)
      return
    }
  }
  reqList.push(url)
}
 
/**
 * 允许某个请求可以继续进行
 * @param {array} reqList 全部请求列表
 * @param {string} url 请求地址
 */
const allowRequest = function (reqList, url) {
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      reqList.splice(i, 1)
      break
    }
  }
}
 
const service = axios.create()
 
// 请求拦截器
service.interceptors.request.use(
  config => {
 let cancel
   // 设置cancelToken对象
    config.cancelToken = new axios.CancelToken(function(c) {
     cancel = c
    })
    // 阻止重复请求。当上个请求未完成时,相同的请求不会进行
    stopRepeatRequest(reqList, config.url, cancel, `${config.url} 请求被中断`)
    return config
  },
  err => Promise.reject(err)
)
 
// 响应拦截器
service.interceptors.response.use(
  response => {
    // 增加延迟,相同请求不得在短时间内重复发送
    setTimeout(() => {
      allowRequest(reqList, response.config.url)
    }, 1000)
    // ...请求成功后的后续操作
    // successHandler(response)
  },
  error => {
    if (axios.isCancel(thrown)) {
      console.log(thrown.message);
    } else {
      // 增加延迟,相同请求不得在短时间内重复发送
      setTimeout(() => {
        allowRequest(reqList, error.config.url)
      }, 1000)
    }
    // ...请求失败后的后续操作
    // errorHandler(error)
  }
)

一些小细节

为什么没用前文方法2中的代码进行cancelToken设置?

axios的文档中有一条备注:

Note: you can cancel several requests with the same cancel token.
你可以使用相同的Token来取消多个请求

所以我不想在每个请求前都new一个新的对象

请务必使用方法2,保证每次cancel都能正确执行。之前方法会导致当出现cancel后,后续请求也会持续cancel

为什么在response中需要增加延迟?

因为不想让用户在极短的时间内重复进行相同请求。

请注意,在response中阻止请求和在request中的阻止请求是两个概念:

request中是阻止上个请求 未完成 时又开始了相同的请求

response中是阻止上个请求 完成后 一段时间内不允许相同请求

我能否在cancel时传递一个对象,而不仅仅是message?

以官方提供的接口来看是不可以的,你可以仿照官方源码进行重新封装,或者使用第三方插件,或者使用另一个方法:将对象转换为JSON字符串,然后在需要的地方再转换回来

标签:axios,请求,url,阻止,reqList,cancel,CancelToken
From: https://www.cnblogs.com/coderz1/p/17130795.html

相关文章

  • 前端使用axios如何提交表单请求
    //使用FormData创建参数letformData=newFormData();formData.append("jsonData",JSON.stringify(reportOptions.request));formDat......
  • curl post请求发送json数据两种方式(Window/Linux)
    curlpost请求发送json数据两种方式(Window/Linux) 设置请求头Content-Typecurl发送post请求,默认的content-type是:application/x-www-form-urlencoded。要发送json格式,......
  • VUE生命周期函数/axios与后端交互案例
    axios发送ajax请求与后端交互以后都用它,在vue上,第三方的模块Axios是一个基于promise的HTTP库,还是基于XMLHttpRequest封装的#跨越问题 -浏览器的原因,只要向不是......
  • 3.drf使用配置&请求封装
    1.drf使用配置1.1安装pipinstalldjangorestframework==3.12.4版本要求djangorestframework==3.12.4python(3.5-3.9)Django(2.2,3.0,3.1)djangor......
  • SpringMVC08 - 处理ajax请求
    SpringMVC处理ajax请求@RequestBody@RequestBody可以获取请求体信息,使用@RequestBody注解标识控制器方法的形参,当前请求的请求体就会为当前注解所标识的形参赋值<!--此......
  • c# 的网络请求相关类
    c#的请求类主要包括HttpWebRequest;WebClient;HttpClient,RestSharp,其中RestSharp是社区的网络请求方案,这里主要是讨论各自的特定HttpWebRequest这个类是.net比较早......
  • C# .NET Post请求API
    1.定义一个POST公共方法 ///HttpWebRequest的POST请求的类型通常有application/x-www-form-urlencoded、application/json、multipart/form-data。///......
  • Axios封装
    实现功能:针对不同请求设置token、code不为成功时的信息提示、code异常情况下的异常处理、屏蔽某些接口、简洁的数据结构响应缺点:1.status为200时,code为401时不会进行无感......
  • 封装axios 到文件 request.js
    importaxiosfrom"axios";import{Message}from"element-ui";//拿token有2种方式:方式1:读取vuex的state;方式2:读取cookieimportstorefrom"@/store";impor......
  • fetch和ajax的区别,fetch请求携带cookie问题
    相关文档链接https://developer.mozilla.org/zh-CN/docs/Web/API/fetchhttps://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetchhttps://developer.......