在vue3项目中实现axios取消某个请求以及全局拦截器阻止重复请求

有时候会遇到一个需求,即需要取消前面的一个或多个请求,就要使用axios的一个方法CancelToken(), 又或者需要全局在项目中对在一定时间段的请求进行去重。比如某些接口返回较慢,用户可能会频繁点击,如果只是单个页面可通过“防抖”处理,如果是多个页面,则需要通过全局接口拦截器进行处理。以上情况有可能在有Loading遮罩时依然发生,所以我们要考虑前端阻止重复请求的方法。

1.借助axios的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();

2.在axios全局拦截器进行请求去重

在main.js导入

import '@/utils/request.js'

utils/request.js

import axios from 'axios'
// 正在进行中的请求列表
let reqList = [] // 如果某个api存在这个数组里,说明该api暂时无法再次请求

/**
 * 阻止重复请求
 * @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
    }
  }
}

// 请求拦截器
axios.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)
)

// 响应拦截器
axios.interceptors.response.use(
  response => {
    // 增加延迟,相同请求不得在短时间内重复发送
    setTimeout(() => {
      allowRequest(reqList, response.config.url)
    }, 1000) // 上一次请求返回后过1s才允许再次请求
    // ...请求成功后的后续操作
    // successHandler(response)
    return response
  },
  error => {
    if (axios.isCancel(error)) {
      console.log(error.message);
    } else {
      // 增加延迟,相同请求不得在短时间内重复发送
      setTimeout(() => {
        allowRequest(reqList, error.config.url)
      }, 1000) // 请求失败返回后过1s才允许再次请求
    }
    // 对请求错误做些什么(比如返回401、403如何处理)
    return Promise.reject(error);
    // ...请求失败后的后续操作
    // errorHandler(error)
  }
)

验证:

使用egg.js写了一个2s才会返回数据的接口,在前端界面通过点击按钮触发请求,通过在2s内点击多次按钮,查看是否仅有一次请求。如果仅有一次,则说明多余请求去重成功。

后台代码(接口2s后返回)
在这里插入图片描述
在前端界面短时间内连续4次点击按钮触发请求
在这里插入图片描述
在这里插入图片描述


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

因为不想让用户在极短的时间内重复进行相同请求。
请注意,在response中阻止请求和在request中的阻止请求是两个概念:
request中是阻止上个请求 未完成 又开始了相同的请求
response中是阻止上个请求 完成后 一段时间内不允许相同请求

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
axios请求拦截器在发送请求之前会拦截请求,并可以对请求进行一些处理。在这个例子,我们可以看到拦截器的配置在引用的`http.interceptors.request.use`函数完成。该函数接受一个参数`config`,代表当前要发送的请求的配置。在这个函数,我们可以根据需要对请求进行一些逻辑判断。 首先,我们可以看到在这个拦截器定义了一个数组`noLanJie`,它包含了一些不需要被拦截的请求地址。如果请求的地址在这个数组存在,那么就直接放行,不做任何处理。 如果请求的地址不在`noLanJie`数组,那么就是需要被拦截的请求。在这个例子拦截器会从本地存储获取到一个名为`token`的值,并将它添加到请求请求的`authorization`字段。这样,在发送请求时,会将这个`token`作为身份验证信息携带到后端。最后,拦截器需要返回`config`对象,以便让请求继续发送。 总结起来,axios请求拦截器可以在发送请求之前对请求进行一些处理,例如添加请求头信息等。拦截器可以根据请求的配置进行逻辑判断,决定是否拦截请求并进行处理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [axios请求拦截器的配置](https://blog.csdn.net/qq_44603011/article/details/123121764)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [vue axios登录请求拦截器](https://download.csdn.net/download/weixin_38655810/13194829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [axios全局拦截+请求响应处理+路由拦截](https://blog.csdn.net/weixin_42484657/article/details/122365109)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值