Axios封装:限制重复请求

目的

1. 当需要发起一个请求之前,可以先取消掉之前的请求,这样确保每次都获取到最新的响应数据,避免数据错乱。

2. 避免用户点击按钮触发了多个相同的网络请求。

AbortController

axios提供了两个取消请求的API,分别是CancelToken和AbortController。但是此 API 从 v0.22.0 开始已被弃用,不应在新项目中使用。

从 v0.22.0 开始,Axios 支持以 fetch API 方式—— AbortController 取消请求:

const controller = new AbortController();

axios.get('/foo/bar', {
   signal: controller.signal
}).then(function(response) {
   //...
});
// 取消请求
controller.abort()

实现思路

1. 如果在当前接口设置了不允许重复请求,那么在请求拦截器中设置AbortController,请求这个接口的时候,拼接接口的url和参数等信息保存到一个map当中

2. 再次请求该接口时,先判断map中是否存在同名key,如果存在,那么调用Abortcontroller的abort方法执行取消,反之则在map当中新增key

// 拼接请求的key
function getRequestKey(config: AxiosRequestConfig) {
  return (config.method || '') + config.url + '?' + qs.stringify(config?.data)
}

function setPendingMap(config: AxiosRequestConfig) {
  const controller = new AbortController()
  config.signal = controller.signal
  const key = getRequestKey(config)
  if (pendingMap.has(key)) {
    pendingMap.get(key).abort()
    pendingMap.delete(key)
  } else {
    pendingMap.set(key, controller)
  }
}

3. 在响应拦截器中,如果map中存在接口的key则删除。

完整代码

// 二次封装axios
import { ElMessage } from 'element-plus'
import useUserStore from '@/store/modules/user'
import qs from 'qs'
import axios, {
  AxiosInstance,
  AxiosError,
  AxiosResponse,
  AxiosRequestConfig,
} from 'axios'

declare module 'axios' {
  export interface AxiosRequestConfig {
    isReturnNativeData?: boolean
    errorMode?: string
    repeatRequest?: boolean
  }
}

const pendingMap = new Map()

function getRequestKey(config: AxiosRequestConfig) {
  return (config.method || '') + config.url + '?' + qs.stringify(config?.data)
}

function setPendingMap(config: AxiosRequestConfig) {
  const controller = new AbortController()
  config.signal = controller.signal
  const key = getRequestKey(config)
  if (pendingMap.has(key)) {
    pendingMap.get(key).abort()
    pendingMap.delete(key)
  } else {
    pendingMap.set(key, controller)
  }
}

const request = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 5000,
})

request.interceptors.request.use(
  (config) => {
    const userStore = useUserStore()

    if (userStore.token) {
      config.headers.token = userStore.token
    }
    if (!config.repeatRequest) {
      setPendingMap(config)
    }

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

request.interceptors.response.use(
  (response) => {
    const config = response.config
    const key = getRequestKey(config)
    pendingMap.delete(key)
    if (response.status === 200) {
      return Promise.resolve(response.data)
    } else {
      return Promise.reject(response.data)
    }
  },
  (error) => {
    let message = ''
    const status = error.response.status
    switch (status) {
      // 401: 未登录
      // 未登录则跳转登录页面,并携带当前页面的路径
      // 在登录成功后返回当前页面,这一步需要在登录页操作。
      case 401:
        message = '未登录'
        break
      // 403 token过期
      // 登录过期对用户进行提示
      // 清除本地token和清空vuex中token对象
      // 跳转登录页面
      case 403:
        message = '登录过期,请重新登录'
        break
      case 404:
        message = '网络请求不存在'
        break
      case 500:
        message = '服务器出现问题'
        break
      default:
        message = error.response.data.message
        break
    }
    ElMessage({
      type: 'error',
      message,
    })
    return Promise.reject(error)
  },
)

export default request
import request from '@/utils/request'

export default {
  getDeptTree: (data: {}) => {
    return request({
      url: '/getDeptTree',
      method: 'post',
      data,
      repeatRequest: false
    })
  }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用axios进行请求时,可以通过封装来实现取消重复请求的功能。以下是一个简单的封装示例: ```javascript import axios from 'axios'; // 创建一个取消请求的CancelToken实例 const cancelToken = axios.CancelToken; const source = cancelToken.source(); // 定义一个变量用于存储重复请求的标识 let pendingRequest = null; // 创建一个axios实例 const instance = axios.create({ baseURL: 'http://api.example.com', timeout: 5000, }); // 请求拦截器 instance.interceptors.request.use(config => { // 如果存在重复请求,则取消之前的请求 if (pendingRequest) { pendingRequest.cancel('canceled due to duplicate request'); } // 存储当前请求 pendingRequest = source; // 将取消标识添加到请求配置中 config.cancelToken = source.token; return config; }, error => { return Promise.reject(error); }); // 响应拦截器 instance.interceptors.response.use(response => { // 请求完成后,将标识置为null pendingRequest = null; return response.data; }, error => { // 请求出错后,将标识置为null pendingRequest = null; return Promise.reject(error); }); export default instance; ``` 在上述示例中,我们通过创建一个取消请求的CancelToken实例和一个变量pendingRequest来管理重复请求。在请求拦截器中,如果存在重复请求,就取消之前的请求并将当前请求存储到pendingRequest变量中。在响应拦截器中,无论请求成功还是失败,都将pendingRequest标识重置为null。 这样,当多次快速发起相同的请求时,只会保留最后一次的请求,之前的请求都会被取消。这样就实现了取消重复请求的功能。 请注意,这只是一个简单的示例,实际应用中可能需要根据具体场景进行适当的修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值