赞
踩
有时候会遇到一个需求,即需要取消前面的一个或多个请求,就要使用axios的一个方法CancelToken(), 又或者需要全局在项目中对在一定时间段的请求进行去重。比如某些接口返回较慢,用户可能会频繁点击,如果只是单个页面可通过“防抖”处理,如果是多个页面,则需要通过全局接口拦截器进行处理。以上情况有可能在有Loading遮罩时依然发生,所以我们要考虑前端阻止重复请求的方法。
在Axios中取消请求最核心的方法是CanelToken。在官网文档中有写到两种方法使用CancelToken,这里简单粘贴出来,并增加了注释
方法1
const CancelToken = axios.CancelToken; const source = CancelToken.source(); axios.get('/user/12345', { // 必须对请求进行cancelToken设置 cancelToken: source.token }).catch(function (thrown) { // 如果请求被取消则进入该方法判断 if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // handle error } }); // 取消上面的请求 // source.cancel('messge') message为可选项,必须为String source.cancel('Operation canceled by the user.');
方法2(推荐):
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
// 在options中直接创建一个cancelToken对象
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
// 取消上面的请求
cancel();
在main.js导入
import '@/utils/request.js'
utils/request.js
import axios from 'axios' // 正在进行中的请求列表 let reqList = [] // 如果某个api存在这个数组里,说明该api暂时无法再次请求 /** * 阻止重复请求 * @param {array} reqList - 请求缓存列表 * @param {string} url - 当前请求地址 * @param {function} cancel - 请求中断函数 * @param {string} errorMessage - 请求中断时需要显示的错误信息 */ const stopRepeatRequest = function (reqList, url, cancel, errorMessage) { const errorMsg = errorMessage || '' for (let i = 0; i < reqList.length; i++) { if (reqList[i] === url) { cancel(errorMsg) return } } reqList.push(url) } /** * 允许某个请求可以继续进行 * @param {array} reqList 全部请求列表 * @param {string} url 请求地址 */ const allowRequest = function (reqList, url) { for (let i = 0; i < reqList.length; i++) { if (reqList[i] === url) { reqList.splice(i, 1) break } } } // 请求拦截器 axios.interceptors.request.use( config => { let cancel // 设置cancelToken对象 config.cancelToken = new axios.CancelToken(function(c) { cancel = c }) // 阻止重复请求。当上个请求未完成时,相同的请求不会进行 stopRepeatRequest(reqList, config.url, cancel, `${config.url} 请求被中断`) return config }, err => Promise.reject(err) ) // 响应拦截器 axios.interceptors.response.use( response => { // 增加延迟,相同请求不得在短时间内重复发送 setTimeout(() => { allowRequest(reqList, response.config.url) }, 1000) // 上一次请求返回后过1s才允许再次请求 // ...请求成功后的后续操作 // successHandler(response) return response }, error => { if (axios.isCancel(error)) { console.log(error.message); } else { // 增加延迟,相同请求不得在短时间内重复发送 setTimeout(() => { allowRequest(reqList, error.config.url) }, 1000) // 请求失败返回后过1s才允许再次请求 } // 对请求错误做些什么(比如返回401、403如何处理) return Promise.reject(error); // ...请求失败后的后续操作 // errorHandler(error) } )
使用egg.js写了一个2s才会返回数据的接口,在前端界面通过点击按钮触发请求,通过在2s内点击多次按钮,查看是否仅有一次请求。如果仅有一次,则说明多余请求去重成功。
后台代码(接口2s后返回)
在前端界面短时间内连续4次点击按钮触发请求
因为不想让用户在极短的时间内重复进行相同请求。
请注意,在response中阻止请求和在request中的阻止请求是两个概念:
request中是阻止上个请求 未完成 又开始了相同的请求
response中是阻止上个请求 完成后 一段时间内不允许相同请求
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。