当前位置: 首页 > news >正文

【cancelToken取消重复请求】

需求背景:

在购物车页面当用不停递进添加或者连续修改时容易触发两次请求,此时第一次请求的结果到来会立刻覆盖用户的第二次输入,因为此时第二次输入的接口数据还没有访问成功,此时数字会先跳变为第一次的结果,然后等第二次请求结束才会再跳变回来,这是不允许的!

虽然通过防抖可以解决左右加减按钮的显示跳变问题,但是如果用户通过输入框在第一次请求已经产生后但是还没有返回数据时立马进行第二次输入时,还是会有跳变问题。

于是就有了cancelToken这篇文章,取消相同的上一次请求达到解决这个需求的目的。

代码:

主要是先——创建一个Map用于存储每个请求的标识和取消函数const pendingMap = new Map();

然后通过——generateKey生成一个唯一的key;

最后——在请求拦截调用addPending,在响应拦截调用removePending实现。

import axios from "axios";
import Vue from 'vue'
import { Message } from "view-design";
import store from '@/store/index';
import router from '@/router/index';
import { getBrowserFingerprint } from '@/common/browser-fingerprint';
import { mdByLogin } from '@/common/common';
let config = {baseURL: process.env.VUE_APP_API,timeout: 60 * 1000, // Timeoutheaders: {'Content-Type': 'application/json'}
};
// console.log("打印Api", process.env.VUE_APP_API);// 创建一个Map用于存储每个请求的标识和取消函数
const pendingMap = new Map()// 生成请求的key
const generateKey = (config) => {const { method, url, params, data } = config// 如果是GET请求,参数在params中;如果是POST请求,参数在data中return [method, url,method === 'get' ? JSON.stringify(params) : JSON.stringify(data)].join('&')
}// 添加请求到Map
const addPending = (config) => {const key = generateKey(config)// 如果已存在相同请求,则取消之前的请求if (pendingMap.has(key)) {const cancelToken = pendingMap.get(key)cancelToken('取消重复请求') // 取消请求pendingMap.delete(key)     // 从Map中删除}// 为当前请求创建取消令牌config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {// 将取消函数存入MappendingMap.set(key, cancel)})
}// 从Map中移除请求
const removePending = (config) => {const key = generateKey(config)if (pendingMap.has(key)) {pendingMap.delete(key)}
}const _axios = axios.create(config);_axios.interceptors.request.use(function (config) {// 在发送请求前,检查并取消重复请求,并将当前请求添加到MapaddPending(config)config.headers['Hipobuy-Client-Type'] = 'WEB';let userTokenInfo = localStorage.getItem('USER_TOKEN');if (userTokenInfo) {config.headers['X-Access-Token'] = userTokenInfo;}let localUserConfig = localStorage.getItem("user_language");if (localUserConfig) {localUserConfig = JSON.parse(localUserConfig);config.headers['lang'] = localUserConfig.code ? localUserConfig.code : process.env.VUE_APP_I18N_LOCALE;} else {config.headers['lang'] = process.env.VUE_APP_I18N_LOCALE;}let userCurrencyConfig = localStorage.getItem("user_currency");if (userCurrencyConfig) {userCurrencyConfig = JSON.parse(userCurrencyConfig);config.headers['currency'] = userCurrencyConfig.code ? userCurrencyConfig.code : process.env.VUE_APP_CURRENCY;} else {config.headers['currency'] = process.env.VUE_APP_CURRENCY;}var client_id = Vue.$cookies.get('_ga') || "";if (client_id.length > 6 && client_id.substring(0, 6) == 'GA1.1.') {config.headers['x-client-id'] = client_id.substring(6);}// 本地是否存在,存在就用,不存在重新获取const browserLocal = localStorage.getItem('BROWSER_RESULT');if (browserLocal) {config.headers['browser_device_id'] = browserLocal;} else {getBrowserFingerprint().then((browserResult) => {if (browserResult && browserResult.visitorId) {localStorage.setItem('BROWSER_RESULT', browserResult.visitorId);config.headers['browser_device_id'] = browserResult.visitorId;}}).catch((error) => {console.log('获取浏览器指纹信息失败:', error);});}if (config.url == '/user/register') {let asb = mdByLogin(`${config.data.email}${config.data.password}`);config.headers['signture'] = asb.signture;config.headers['timestamp'] = asb.timestamp;}return config;},function (error) {// Do something with request errorreturn Promise.reject(error);}
);// Add a response interceptor
_axios.interceptors.response.use(function (response) {// 请求完成,移除Map中的记录removePending(response.config)// Do something with response dataif (response.data.code == 200 || response.data.code == 201 || response.data.code == 0) {return response.data;} else if (response.data.code == 401) {store.commit('resetUserInfo');router.push({path: '/login'});} else if (response.data.code == 1002) {return response.data;} else if (response.data.code == 1010) {// 禁搜状态return response.data;} else {// 当messageState 状态是true的时候显示弹窗,处理多个请求,弹窗出多个错误信息if (store.state.app.messageState) {store.commit('setMessageState');Message.error({content: response.data.message,background: true,duration: 8,closable: true,onClose: () => {store.commit('setMessageState');}})}return Promise.reject(response.data);}return Promise.reject(response.data);
},function (error) {console.log(error.response);// Do something with response errorif (error.response.status == 401) {store.commit('resetUserInfo');let filterRouter = ['/', '/login', '/register', '/forgot', '/loginToken', '/goods', '/product', '/estimation', '/shopWindow', '/notice', '/help', '/issueView', '/beginner-guide'];let currentPath = window.location.pathname;let isValueIncluded = filterRouter.some(route => {if (route === '/') {// 首页只匹配完全等于 '/' 的路径return currentPath === '/';} else {// 其他路径使用 startsWith 匹配return currentPath.startsWith(route);}});// 调试信息// console.log('当前路径:', currentPath);// console.log('是否在白名单:', isValueIncluded);// console.log('白名单列表:', filterRouter);// 特殊处理:如果是产品页面且是用户主动操作(如加入购物车、购买),则跳转登录if (currentPath.startsWith('/product') && error.config && error.config.url &&(error.config.url.includes('/addV2') || error.config.url.includes('/buy') || error.config.url.includes('/cart'))) {router.push({path: '/login',query: { ...router.currentRoute.query, redirection: router.currentRoute.fullPath }});} else if (!isValueIncluded) {// 其他页面不在白名单中,跳转登录router.push({path: '/login',query: { ...router.currentRoute.query, redirection: router.currentRoute.fullPath }});}// 在白名单中的页面(包括产品页面非用户操作),不跳转登录}if (error.response.data.code == 5000) {// 风控弹框return Promise.reject(error.response.data);} else if (error.response.data.code == 8000) {// paypal支付弹框return Promise.reject(error.response.data);} else if (error.response.data.code == 8001) {// klarna支付异常弹框return Promise.reject(error.response.data);}return Promise.reject(error);}
);export default _axios;

http://www.xdnf.cn/news/1405585.html

相关文章:

  • uniapp开发 移动端使用字符串替换注意事项
  • GEE中上传研究区域范围
  • ModuleNotFoundError: No module named ‘_cffi_backend‘
  • 服务器CPU飙升该如何排查火焰图
  • 互联网医院系统优势介绍
  • Java试题-选择题(22)
  • 诊断通信管理(Diagnostic Communication Management)详解
  • Shell脚本命令扩展
  • Langflow核心技术学习笔记(新)
  • 针对 “TCP 数据传输机制” 的攻击
  • STL中的容器,迭代器
  • DAY 18 推断聚类后簇的类型 - 2025.8.30
  • Megatron-LM(模型并行)
  • 2025 年 AI 发展十大预测:多模态融合、边缘 AI 普及将成核心增长点
  • Redis数据类型概览:除了五大基础类型还有哪些?
  • 【适度精简】Windows 7 旗舰版-emmy精简系统
  • SpringAI应用开发工程师高阶面试剧本与知识点全解析(含RAG、多租户、流式推理、企业落地场景)
  • leetcode2(移除元素)
  • windows32位下载谷歌浏览器的地址
  • Twitter舆情裂变链:指纹云手机跨账号协同机制提升互动率200%
  • 大数据在UI前端的应用深化研究:用户行为数据的跨平台关联分析
  • 优化器全指南:从原理到调优实战
  • DrissionPage 实战:高效爬取网页数据并保存为 CSV 的全流程解析
  • 什么是雪花算法
  • Western Blot 样本制备完整流程:从细胞 / 组织到变性样品的关键步骤与细节
  • Selenium自动化测试快速入门指南
  • 玄机靶场 | 第五届红明谷-异常行为溯源
  • MCP进阶指南:如何挑选最适合你的AI助手“装备“
  • [光学原理与应用-332]:ZEMAX - 序列模式与非序列模式的本质、比较
  • JavaScript 中的 this 关键字