Axios 如何取消重复请求

Axios 如何取消重复请求


重复请求是如何产生的呢?这里我们举 2 个常见的场景:

  1. 假设页面中有一个按钮,用户点击按钮后会发起一个 AJAX 请求。如果未对该按钮进行控制,当用户快速点击按钮时,则会发出重复请求(备注:此场景防抖方法更适用,因为还是会发到后端,只是浏览器不会处理)
  2. 假设vue页面加载时会调一次接口,监听到某个值会调一次相同接口,第一次调的接口返回比第二次慢,导致最后获取到的数据是第一次接口返回的数据,

注:一般可以再加个白名单,允许重复请求,此方法还是会发到后端,只是浏览器不会处理

http.ts 文件

import axios, { AxiosRequestConfig } from 'axios'
import { Toast, Notify, Dialog } from 'vant'
import router from '@/router/index'

interface BaseResponse<T = any> {
  code: number
  data: T
  message: string
}
const instance = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API
})

//根据当前请求的信息,生成请求 Key
const generateReqKey = (config: AxiosRequestConfig) => {
  const { method, url, params, data } = config
  //通过url和method双重校验
  return [method, url].join('&')
}
//把当前请求信息添加到pendingRequest对象中
const pendingRequest = new Map()
const addPendingRequest = (config: AxiosRequestConfig) => {
  const requestKey = generateReqKey(config)
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken(cancel => {
      if (!pendingRequest.has(requestKey)) {
        pendingRequest.set(requestKey, cancel)
      }
    })
}
//检查是否存在重复请求,若存在则取消已发的请求
const removePendingRequest = (config: AxiosRequestConfig) => {
  const requestKey = generateReqKey(config)
  if (pendingRequest.has(requestKey)) {
    const cancelToken = pendingRequest.get(requestKey)
    cancelToken(requestKey)
    pendingRequest.delete(requestKey)
  }
}

instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    //断网提示
    if (!navigator.onLine) {
      Notify({ type: 'warning', message: '您的网络故障,请检查!' })
    }
    if (localStorage.getItem('token')) {
      config.headers.token = localStorage.getItem('token')
    }
    removePendingRequest(config) // 检查是否存在重复请求,若存在则取消已发的请求
    addPendingRequest(config) // 把当前请求信息添加到pendingRequest对象中
    return config
  },
  error => {
    // console.log('请求拦截error', error)
    return Promise.reject(error)
  }
)

// interface TipsMessage {
//   [propName: number]: string
// }

// const tipsMessage: TipsMessage = {
//   100: '登录失败  用户名密码不对或账号被锁定',
//   101: 'TOKEN失效  Token已失效,请重新调登录接口',
//   102: '参数错误  请根据接口参数要求进行传参',
//   103: '未登录',
//   300: '接口无访问权限  没有权限访问该接口',
//   301: '数据无访问权限  没有权限访问该设备数据',
//   302: '服务到期  设备服务到期 '
// }

instance.interceptors.response.use(
  response => {
    // setTimeout(() => {
    //   hideLoading()
    // }, 200)
    // console.log(response)
    removePendingRequest(response.config) // 从pendingRequest对象中移除请求
    const { code, message } = response.data
    if (code !== 0 && code !== 200) {
      if (code === 1011008 || code === 103 || code === 1011006) {
        Dialog.alert({
          title: '温馨提示',
          message: '当前用户没有登录或登录失效,需要重新登录'
        }).then(() => {
          localStorage.clear()
          // router.push({ name: 'Login' })
          // store.commit('logout')
          location.reload() // 为了重新实例化vue-router对象 避免bug
        })
      } else if (code === 20330033) {
        // 未设置支付密码
        router.push({
          name: 'SetPayPassword'
        })
      } else {
        Toast.fail(message)
        //  Toast.fail(`${tipsMessage[code]}`)
      }
      return Promise.reject(message)
    } else {
      return response
    }
  },
  error => {
    // setTimeout(() => {
    //   hideLoading()
    // }, 200)
    // console.log('http response - err', error)
    removePendingRequest(error.config || {}) // 从pendingRequest对象中移除请求
    if (axios.isCancel(error)) {
      // console.log('已取消的重复请求:' + error.message)
    } else {
      // 添加异常处理
      Toast.fail('服务器异常,请稍后再试')
    }
    return Promise.reject(error)
  }
)

const request = <T = any>(config: AxiosRequestConfig): Promise<T> => {
  return new Promise((resolve, reject) => {
    instance
      .request<BaseResponse<T>>(Object.assign(config))
      .then(res => resolve(res.data.data))
      .catch(err => reject(err))
  })
}

export default request

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值