axios拦截器之重复请求取消上次请求、路由切换取消接口

在项目中经常会遇到需要主动取消接口的场景,axios提供CancelToken的功能可以主动停止当前请求,从而避免无效请求,优化网络性能

场景:

  1. 远程搜索接口频繁请求,第二个接口先成功导致显示第一个接口返回的数据
  2. 前端切换路由,前一个路由的接口用不到了,但还在请求中

这两种情况可以单独在组件中使用CancelToken来取消接口请求,但是如果要主动请求的接口较多,则会照成代码冗余,于是需要封装成一个公共的方法

1、搭载请求容器及处理方法:cancel-request.js 

  • pengdingList: 盛放接口处于pengding(请求中)状态的容器,key是接口唯一标识,value是该接口的cancel请求的方法

  • getFetchKey: 生成接口唯一标识的方法

  • addPending:把请求加到pending容器的方法

  • removePending:把请求从pengding容器中移除的方法

  • cancelPending:取消请求并从pengding中移除的方法

/**
 * 重复请求取消上次请求
 */
import axios from 'axios'
// 存储pengding请求容器
export const pendingList = new Map()
// 生成各个请求标识
export const getFetchKey = (config) => {
    const { url, data, method } = config
    let token
    if (method === 'get') {
        token = [method, url].join('&')
    } else {
        token = [method, url, JSON.stringify(data)].join('&')
    }
    return token
}
// 添加pengding请求
export const addPending = (config) => {
    const fetchKey = getFetchKey(config)
    if (fetchKey) {
        config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
            if (!pendingList.has(fetchKey)) {
                pendingList.set(fetchKey, cancel)
            }
        })
    }
}
// 移除pengding请求
export const removePending = (config) => {
    const fetchKey = getFetchKey(config)
    if (fetchKey) {
      if (pendingList.has(fetchKey)) {
        pendingList.delete(fetchKey)
      }
    }
}
// 取消请求
export const cancelPending = (config) => {
    const fetchKey = getFetchKey(config)
    if (fetchKey) {
      if (pendingList.has(fetchKey)) {
        const cancel = pendingList.get(fetchKey)
        cancel('cancel')
        pendingList.delete(fetchKey)
      }
    }
}

2、axios拦截器配置-防止频繁请求

  • 请求时判断是否该请求是否重复,如果重复取消之前的请求
  • 请求时把当前请求加入pending容器中
  • 相应成功或失败时把当前请求从pending容器中移除
/**
 * axios拦截器配置
*/
import {
    addPending, removePending, cancelPending,
} from '@util/cancel-request'
import axios from 'axios'
// 请求拦截器
axios.interceptors.request.use(
    request => {
        // 发送请求前首先检查该请求是否已经重复,重复则进行取消并移除
        cancelPending(request)
        // 添加该请求到pendingList中
        addPending(request)
        return request
    },
    error => {
        return Promise.error(error)
    }
)
axios.interceptors.response.use(
    response => {
        // 请求成功去除pengding状态
        removePending(response)
        if (response.status === 200) {
            return Promise.resolve(response)
        } else {
            return Promise.reject(response)
        }
    },
    error => {
        // 请求失败去除pengding状态
        removePending(error.response)
        return Promise.reject(error.response)
    }
)

3、切换路由取消之前页面的pending状态的请求-beforEach(react用路由组件判断)

  • 在beforEach方法中获取所有pending状态的接口(pengding容器)
  • 对pending容器进行循环,依次取消
  • 清空pengding容器
import { pendingList } from '@util/cancel-request'

router.beforeEach((to, from, next) => {
    let pengdingArr = pendingList.values()
    let current = pengdingArr.next()
    while (!current.done) {
        current.value('cancel')
        current = pengdingArr.next()
    }
    pendingList.clear()
    next()
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值