axios拦截器之重复请求取消上次请求

1,335 阅读1分钟

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

场景: 远程搜索接口频繁请求,第二个接口先成功导致显示第一个接口返回的数据

/**
 * 重复请求取消上次请求
 */
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)
      }
    }
}

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)
    }
)