npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

st-duplicate-request-axios

v1.1.2

Published

针对于axios防止重复请求接口,避免浪费资源

Readme

介绍:

在现代的前端开发中,与后端进行数据交互是一个非常常见的任务。然而,我们经常会遇到一个令人头疼的问题:请求重复提交。当用户在某个操作上频繁点击或者网络延迟导致请求未完成时,重复提交请求会带来一系列问题,如重复创建数据、产生不一致的状态等,给用户体验和数据完整性带来困扰。

为了解决这个问题,我封装了一款的工具:St-Duplicate-Request-Axios。这个工具基于 Vue 3 和 Axios,并提供了一个自定义 Hook,帮助开发者轻松处理请求重复提交的场景,从而提升开发效率。

使用方法

  1. 首先,安装依赖包。在终端中运行以下命令:
npm i st-duplicate-request-axios
  1. 在需要使用的文件中引入 useStDuplicateRequestAxios 函数,并创建一个实例:
import axios from "axios"
import { useStDuplicateRequestAxios } from "st-duplicate-request-axios"
const duplicateRequest = useStDuplicateRequestAxios(axios)
  1. 现在,你可以在发送请求之前使用 duplicateRequest.addRequest 函数将请求添加到请求队列中。如果队列中已存在相同的请求,则会取消重复的请求:
// 请求拦截
serve.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    duplicateRequest.addRequest(config) // 添加进请求队列
    ...
    return config
}, (error: AxiosError) => {
    return Promise.reject(error)
})
  1. 当请求完成时,使用 duplicateRequest.removeRequest 函数将请求从队列中移除:
// 响应拦截
serve.interceptors.response.use((response: AxiosResponse) => {
    duplicateRequest.removeRequest(response.config) // 移除请求队列
   ...
    return response
}, (error: AxiosError) => {
    message.warning(error.message)
    return Promise.reject(error)
})
  1. 你也可以传入两个可选的回调函数:重复请求回调函数和移除请求回调函数。
// 重复请求回调函数
const handleDuplicateRequest = (cancel, config, requestQueue) => {
  console.log("发现重复请求,取消当前请求:", config.url)
  cancel("请求重复,已取消") // 可自定义取消请求的错误信息
}

// 移除请求回调函数
const handleRemoveRequest = (config, requestQueue) => {
  console.log("请求完成,从队列中移除:", config.url)
}

// 请求拦截器
axios.interceptors.request.use(
  (config) => {
    duplicateRequest.addRequest(config, handleDuplicateRequest) // 添加进请求队列并传入重复请求回调函数
    // 其他逻辑...
    return config
  },
  (error: AxiosError) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
axios.interceptors.response.use(
  (response) => {
    duplicateRequest.removeRequest(response.config, handleRemoveRequest) // 移除请求队列并传入移除请求回调函数
    // 其他逻辑...
    return response
  },
  (error: AxiosError) => {
    // 错误处理逻辑...
    return Promise.reject(error)
  }
)

代码实现:

  1. 导入必要的依赖和类型声明:

    import { AxiosStatic, InternalAxiosRequestConfig, Canceler } from "axios"
    import { reactive } from "vue"
    import { isEqual } from "lodash-es"

    这段代码导入了 Axios 相关的类型声明和必要的依赖,包括 AxiosStatic、InternalAxiosRequestConfig 和 Canceler,以及 reactive 方法用于创建响应式对象,和 isEqual 方法用于比较数据的相等性。

  2. 创建请求队列和数据归一化函数:

    const requestQueue = reactive<InternalAxiosRequestConfig[]>([])
    
    type DataType = object | string
    
    const _formatData = (data: DataType) => {
        if (typeof data === "string") {
            try {
                return JSON.parse(data)
            } catch (error) {
                return {}
            }
        } else if (typeof data === "object") {
            return data
        } else {
            return {}
        }
    }

    这段代码创建了一个响应式的请求队列 requestQueue,用于存储待发送的请求配置。_formatData 函数用于将数据归一化,将数据统一转换为对象形式。

  3. 获取请求队列中存在的索引:

    typescriptCopy code
    const _getArrayIndex = (config: InternalAxiosRequestConfig) => {
        if (!requestQueue.length) return -1;
        else return requestQueue.findIndex((queueConfig: InternalAxiosRequestConfig) => {
            return (queueConfig.url === config.url && isEqual(_formatData(config.data), _formatData(queueConfig.data)))
        })
    }

    这段代码实现了一个函数 _getArrayIndex,用于获取请求队列中与指定请求配置相同的请求的索引。它会遍历请求队列中的配置,判断 URL 和数据是否相同,如果找到相同的请求,则返回其索引,否则返回 -1。

  4. 添加请求到队列中:

    const addRequest = (config: InternalAxiosRequestConfig, repeatCb?: repeatCbType) => {
        if (!requestQueue.length || _getArrayIndex(config) === -1) {
            requestQueue.push(config)
        } else {
            config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
                if (repeatCb) repeatCb(cancel, config, requestQueue);
                else cancel(`请求重复,请求地址:${config.url}`)
            })
        }
    }

    这段代码定义了 addRequest 函数,用于将请求配置添加到请求队列中。如果请求队列为空或者不存在相同的请求,则将请求配置添加到队列中;否则,会使用 axios 提供的 CancelToken 取消重复的请求,并执行 repeatCb 回调函数(如果提供的话)。

  5. 从队列中移除完成的请求:

    const removeRequest = (config: InternalAxiosRequestConfig, removedSuccessCb?: removedSuccessCbType) => {
        if (requestQueue.length) {
            const index = _getArrayIndex(config)
            if (index !== -1) requestQueue.splice(index, 1)
            removedSuccessCb && removedSuccessCb(config, requestQueue)
        }
    }

    这段代码实现了 removeRequest 函数,用于从请求队列中移除已完成的请求配置。它会找到与指定请求配置相同的请求,并将其从队列中移除。移除成功后,会执行 removedSuccessCb 回调函数(如果提供的话)。

    addRequest 和 removeRequest 函数是我们保留出来的两个函数,用于处理请求的重复提交。

import { AxiosStatic, InternalAxiosRequestConfig, Canceler } from "axios"
import { reactive } from "vue"
import { isEqual } from "lodash-es"

// st-no-duplicate-request-axios
export function useStDuplicateRequestAxios(axios: AxiosStatic) {
    const requestQueue = reactive<InternalAxiosRequestConfig[]>([])

    type DataType = object | string
    /**
     * 数据归一化
     * @param data 
     * @returns 
     */
    const _formatData = (data: DataType) => {
        if (typeof data === "string") {
            try {
                return JSON.parse(data)
            } catch (error) {
                return {}
            }
        } else if (typeof data === "object") {
            return data
        } else {
            return {}
        }
    }


    /**
     * 获取请求队列中存在的索引
     * @param config 
     * @returns 
     */
    const _getArrayIndex = (config: InternalAxiosRequestConfig) => {
        if (!requestQueue.length) return -1;
        else return requestQueue.findIndex((queueConfig: InternalAxiosRequestConfig) => {
            return (queueConfig.url === config.url && isEqual(_formatData(config.data), _formatData(queueConfig.data)))
        })
    }


    /**
     * 如果请求队列中没有一样的请求,就加入到请求队列中,否则则取消请求
     * @param config 
     * @param repeatCb Function 
     */
    const addRequest = (config: InternalAxiosRequestConfig, repeatCb?: repeatCbType) => {
        if (!requestQueue.length || _getArrayIndex(config) === -1) {
            requestQueue.push(config)
        } else {
            config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
                if (repeatCb) repeatCb(cancel, config, requestQueue);
                else cancel(`请求重复,请求地址:${config.url}`)
            })
        }
    }


    /**
     * 请求完成,把请求从队列中移除
     * @param config 
     * @param removedSuccessCb 移除成功的回调函数
     */
    const removeRequest = (config: InternalAxiosRequestConfig, removedSuccessCb?: removedSuccessCbType) => {
        if (requestQueue.length) {
            const index = _getArrayIndex(config)
            if (index !== -1) requestQueue.splice(index, 1)
            removedSuccessCb && removedSuccessCb(config, requestQueue)
        }
    }


    return {
        addRequest,
        removeRequest
    }
}

使用上述代码,我们可以在 Vue 3 项目中轻松地处理请求的重复提交问题。addRequest 函数用于将请求添加到请求队列中,如果队列中已存在相同的请求,则会取消重复的请求;removeRequest 函数用于从请求队列中移除已完成的请求。

这个自定义的 Hook 可以帮助我们优化项目中的请求处理,避免重复提交请求,提高系统的性能和用户体验。在使用时,我们只需引入该 Hook,并在需要的地方调用 addRequest 和 removeRequest 函数即可。

特点

  1. 简单易用:只需要引入 St-Duplicate-Request-Axios,然后使用自定义的 Hook,就可以快速集成到你的项目中。
  2. 自动处理重复请求:无需手动编写逻辑判断重复请求,工具会自动根据请求的 URL 和数据判断是否重复,并进行处理。
  3. 数据归一化:通过归一化请求数据,保证数据内容相同的请求也能被正确判断为重复请求。
  4. 灵活定制:可以自定义重复请求的处理逻辑,例如弹出提示、取消请求等,以适应不同的业务场景。

结语:

useStDuplicateRequestAxios 自定义 Hook 的出现,为我们解决了请求重复提交的痛点。通过简洁而强大的代码,我们能够轻松应对各种复杂的请求场景,提高代码的可读性和维护性。无论是大型项目还是小型应用,使用 useStDuplicateRequestAxios 都能够极大地减少开发工作量,加快开发进度。

让我们一起解放双手,优化前端开发!