众所周知,我们在项目开发过程中难免会遇到重复请求的处理(用户快速点击按钮,触发调用接口操作),下面是实现防止重复请求的实现方案
-
方案1
这个方案是最容易想到也是最朴实无华的一个方案:通过使用axios拦截器,在请求拦截器中开启全屏Loading,然后在响应拦截器中将Loading关闭。
这个方案固然已经可以满足我们目前的需求,但不管三七二十一,直接搞个全屏Loading还是不太美观,何况在目前项目的接口处理逻辑中还有一些局部Loading,就有可能会出现Loading套Loading的情况,两个圈一起转,头皮发麻。
-
方案2
加Loading的方案不太友好,而对于同一个接口,如果传参都是一样的,一般来说都没有必要连续请求多次吧。那我们可不可以通过代码逻辑直接把完全相同的请求给拦截掉,不让它到达服务端呢?这个思路不错,我们说干就干。
首先,我们要判断什么样的请求属于是相同请求:
一个请求包含的内容不外乎就是请求方法,地址,参数以及请求发出的页面hash。那我们是不是就可以根据这几个数据把这个请求生成一个key来作为这个请求的标识呢?
// 根据请求生成对应的key function generateReqKey(config, hash) { const { method, url, params, data } = config; return [method, url, JSON.stringify(params), JSON.stringify(data), hash].join("&"); }
有了请求的key,我们就可以在请求拦截器中把每次发起的请求给收集起来,后续如果有相同请求进来,那都去这个集合中去比对,如果已经存在了,说明就是一个重复的请求,我们就给拦截掉。当请求完成响应后,再将这个请求从集合中移除。合理,nice!
具体实现如下:
import axios from 'axios'; const instance = axios.create({ baseUrl: '/api/', }); // 根据请求生成对应的 key function generateReqKey(config, hash) { const { method, url, params, data } = config; return [method, url, JSON.stringify(params), JSON.stringify(data), hash].join('&'); } // 存储已发送但未响应的请求 const pendingRequest = new Set(); // 添加请求拦截器 instance.interceptors.request.use(function (config) { const hash = location.hash; // 生成请求 Key const reqKey = generateReqKey(config, hash); if (pendingRequest.has(reqKey)) { return Promise.reject(