Vue Axios请求取消和重发封装的实现代码
作者:墨辰mc
这篇文章主要介绍了Vue Axios请求取消和重发的封装的实现,文章通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
场景
如图,有时候请求后端同一接口时,会因接口响应速度过慢,导致前端原本页面应显示a,结果显示b。像上图,前端页面看起来就是先显示 请求b 的数据,然后是 请求c 的数据,最后是 请求a 的数据,但是实际上我们只需要显示最后的 请求c 的数据。而且这样还会导致页面渲染出现闪烁。
需求
- 实现取消重复请求(有多种取消方式)
- 发出第一个请求,取消后面的相同请求
- 取消前面的请求,只发出最后一个请求
- 实现请求失败后,自动重发指定次数
实现1(发出第一个请求,取消后面的相同请求)
import Axios from "axios"; // 创建一个实例 const service = Axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 1000, }); // 添加请求拦截器 service.interceptors.request.use( (config) => { // 判断是否有 token if (getToken()) { config.headers["Permission-Token"] = getToken(); } // 添加待处理请求 addPendingRequest(config); return config; }, (error) => { return Promise.reject(error); } ); // 添加响应拦截器 service.interceptors.response.use( (response) => { // 移除挂起的请求 removePendingRequest(response); const res = response.data; return res; }, (error) => { // 移除挂起的请求 removePendingRequest(error); // 是否是取消请求 if (Axios.isCancel(error)) { console.log("err:", error); return Promise.reject(error); } else { console.log("请求有问题:", error.message); // 当请求超时、断网等问题时重发 return againRequest(error); } } ); export default service; const pendingRequest = new Map(); /** * 添加待处理请求 * @description 该函数用于管理重复请求,避免同一接口的多个请求同时进行 * @param {Object} config - axios请求配置对象 */ function addPendingRequest(config) { // 创建axios的取消令牌源,用于请求的取消控制 const CancelToken = axios.CancelToken; const source = CancelToken.source(); // 生成请求的唯一键,用于标识不同的请求 const requestKey = generateReqKey(config); // 方法一 // 如果相同请求已在进行中,则取消当前请求 if (pendingRequest.has(requestKey)) { config.cancelToken = source.token; source.cancel(`${config.url} 请求已取消`); } else { // 如果没有相同的请求在进行中,则设置取消令牌并存储请求键和取消函数的映射 config.cancelToken = source.token; pendingRequest.set(requestKey, source.token); } // 方法二 // 如果相同请求已在进行中,则取消当前请求 if (pendingRequest.has(requestKey)) { config.cancelToken = new Axios.CancelToken((cancel) => { // cancel 函数的参数会作为 promise 的 error 被捕获 cancel(`${config.url} 请求已取消`); }); } else { config.cancelToken = new Axios.CancelToken((cancel) => { pendingRequest.set(requestKey, cancel); }); } // 以上两种方式都能取消请求,但是从 Axios `v0.22.0` 开始已被弃用,从 `v0.22.0` 开始,Axios 支持以 fetch API 方式—— `AbortController`取消请求 } /** * 移除挂起的请求 * @description 当收到响应时,检查并移除与该响应相关的挂起请求 * @param {Object} response - 响应对象,包含请求配置信息 */ function removePendingRequest(response) { // 如果 response.config 返回的是 undefined,表示是取消请求,则不处理 if (response.config) { // 生成请求的唯一键,用于标识不同的请求 const requestKey = generateReqKey(response.config); // 判断是否有这个 key,有就删除 if (pendingRequest.has(requestKey)) { pendingRequest.delete(requestKey); } } } /** * 处理请求重试的函数 * @description 它尝试重新发送因错误而失败的请求 * @param {Object} err - 包含错误信息和配置的对象 * @returns {Promise} 重新发送请求的Promise对象,解决或拒绝依据重试逻辑 */ function againRequest(err) { const config = err.config; // 如果配置对象不存在,则直接拒绝Promise if (!config) return Promise.reject(err); // 设置用于记录重试计数的变量 默认为0 config._retryCount = config._retryCount || 0; // 如果重试次数已经达到3次或更多,则拒绝Promise if (config._retryCount >= 3) { return Promise.reject(err); } // 重试次数 config._retryCount += 1; // 延时处理,用于控制重试的时间间隔 var backoff = new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }); // 在延时结束后,重新发起请求 return backoff.then(() => { // 重新发起axios请求,使用更新后的配置 return service(config); }); } /** * 生成请求的唯一键 * @description 这个函数的目的是根据请求配置生成一个唯一的键,用于缓存请求数据 * @param {Object} config - 请求配置对象,包含了url、method、params和data属性 * @returns {string} - 返回一个根据请求配置生成的唯一键 */ function generateReqKey(config) { // 请求得到的config.data是对象格式,响应回来的response.config.data是字符串格式,需要转换成对象 if (typeof config.data === "string") { config.data = JSON.parse(config.data); } const { url, method, params, data } = config; return [url, method, JSON.stringify(params), JSON.stringify(data)].join("&"); }
实现2(取消前面的请求,只发出最后一个请求)
import Axios from "axios"; // 创建一个实例 const service = Axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 1000, }); // 添加请求拦截器 service.interceptors.request.use( (config) => { // 判断是否有 token if (getToken()) { config.headers["Permission-Token"] = getToken(); } // 添加待处理请求 addPendingRequest(config); return config; }, (error) => { return Promise.reject(error); } ); // 添加响应拦截器 service.interceptors.response.use( (response) => { const res = response.data; return res; }, (error) => { // 是否是取消请求 if (!axios.isCancel(error)) { // 当请求超时、断网等问题时重发 againRequest(error); } } ); export default service; let pendingRequsetList = []; /** * 取消所有待处理的请求 */ export const cancelPendingRequest = () => { // 遍历待处理的请求列表,调用每个请求的取消方法 pendingRequsetList.forEach((item) => { item.cancel(); }); // 清空待处理的请求列表 pendingRequsetList = []; }; /** * 添加待处理的请求 * @description 为配置对象添加取消令牌,以便在请求待处理时能够取消 * @param {Object} config - 请求的配置对象 */ function addPendingRequest(config) { // 创建一个新的取消令牌,并将取消函数存储到待处理请求列表中 config.cancelToken = new Axios.CancelToken((cancel) => { pendingRequsetList.push({ cancel, }); }); } /** * 处理请求失败后的重试机制 * @description 当请求失败时,尝试再次请求,最多重试3次 * @param {Object} err - 错误对象,包含请求的配置信息 * @returns {Promise} 重试请求的Promise对象 */ function againRequest(err) { // 获取请求的配置信息 const config = err.config; // 如果没有配置信息,则直接拒绝Promise if (!config) Promise.reject(err); // 初始化重试次数,如果不存在则为0 config._retryCount = config._retryCount || 0; // 如果重试次数已经达到3次,则拒绝Promise if (config._retryCount >= 3) { return Promise.reject(err); } // 每次重试前,重试次数加1 config._retryCount += 1; // 创建一个Promise,用于实现指数退避机制 const backoff = new Promise((resolve) => { // 设置一个定时器,1秒后 resolve Promise setTimeout(() => { resolve(); }, 1000); }); // 返回一个Promise,表示再次请求的操作 return backoff.then(() => { return service(config); }); }
在组件中使用,发送一个新的请求之前,取消前面的所有正在请求的请求,如下:
<script> import { cancelPendingRequest } from '@/utils/request' // 导入取消请求的方法 export default { methods: { getList() { cancelPendingRequest() // 取消所有正在发送请求的请求 axios.get() // 发送新的请求 } } } </script>
如果不想每次使用取消请求的时候都需要导入那么可以挂载到Vue的原型上面,可以在main.js
文件中
import Vue from 'vue' import { cancelPendingRequest } from '@/utils/request' Vue.prototype.$cancelPendingRequest = cancelPendingRequest // 挂载到 Vue 原型上
另外如果想每次路由页面跳转时,取消上一个页面的所有请求,我们可以在全局路由守卫那里进行处理,具体如下:
import router from "./router"; import Vue from 'vue' router.beforeEach((to, from, next) => { Vue.$cancelPendingRequest() // 跳转页面之前取消之前的所有请求 })
以上就是Vue Axios请求取消和重发的封装的实现的详细内容,更多关于Vue Axios请求取消和重发的资料请关注脚本之家其它相关文章!