【接口重复请求】axios通过AbortController解决页面切换过快,接口重复请求问题

处理网络请求时,我们经常会遇到需要中途取消请求的情况,比如用户在两个tab之间反复横跳的场景,如果每个接口都从头请求到结束,那必然会造成很大的服务压力。

AbortController是一个Web API,它提供了一个信号对象(AbortSignal),该对象可以用来取消与Fetch API相关的操作。当我们创建AbortController实例时,会自动生成一个与之关联的AbortSignal对象。我们可以将这个AbortSignal对象作为参数传递给fetch函数,从而实现对网络请求的取消控制。

javascript 复制代码
import axios from 'axios'
import QS from 'qs'//引入qs模块,用来序列化post类型的数据

// 创建map存储未返回response的接口请求
const pendingRequests = new Map();

const generateRequestKey = (config) => {
    // 处理请求数据,确保请求和响应时一致,response返回的config中可能存在序列化的data,需要转换成json格式,否则生成的key不一致
    const normalizeData = (data) => {
      if (typeof data === 'string') {
        try {
          return JSON.parse(data);
        } catch {
          return data;
        }
      }
      return data;
    };
    
    return [
      config.method,
      config.url,
      JSON.stringify(normalizeData(config.params) || {}),
      JSON.stringify(normalizeData(config.data) || {})
    ].join('|');
  };

axios.defaults.baseURL = '/';
axios.defaults.timeout = 10000;
axios.defaults.headers.post['Content-Type'] = 'application/json';
// 如果需要跨域,可以设置withCredentials为true
axios.defaults.withCredentials = true; // 允许跨域请求时发送cookies


// 创建axios实例
const service = axios.create({
    baseURL: '/api', // api的base_url
    timeout: 10000,// 请求超时时间
    headers: {
        'Access-Control-Allow-Origin': '*',
        'strict-origin-when-cross-origin': '*',
        'Cache-Control': 'no-cache',
        'Content-Type': 'application/x-www-form-urlencoded',
        'userRole': 'WEB',
        'Accept-Language': i18n.locale || localStorage.getItem('Accept-Language')
    }
});

// 请求拦截器
service.interceptors.request.use(config => {
    config.headers['nh-token'] = localStorage.getItem('NH_TOKEN') || ""
    const token = localStorage.getItem('newToken') || ""
    if (token) config.headers['Authorization'] = 'Bearer ' + token // 新服务添加token
    
    // 生成请求key,用于取消重复的相同请求
    const requestKey = generateRequestKey(config, 'service.interceptors.request');
    // 如果存在相同请求,取消前一个
    if (pendingRequests.has(requestKey)) {
        const abortController = pendingRequests.get(requestKey);
        abortController.abort();
    }
    
    // 为当前请求创建新的控制器
    const controller = new AbortController();
    config.signal = controller.signal;
    pendingRequests.set(requestKey, controller);
    
    return config;
},
    error => {
        return Promise.error(error);
    })
// 响应拦截器
service.interceptors.response.use(
    response => {
        const requestKey = generateRequestKey(response.config, 'service.interceptors.response');
        pendingRequests.delete(requestKey);
        // console.log('Response=>', response.request.responseURL, response  );
        if (response.status === 200) {
            //result  0-正常  1-异常  10000-未登录 4000-系统异常
            if (response.data.result == 10000) {
                // 登录失败,跳转到首页,重新登录
                router.push({ path: '/login' })
                return Promise.resolve(response.data)
            } else {
                return Promise.resolve(response.data)
            }
        } else {
            return Promise.reject(response);
        }
    },
    error => {
        if (error.name === 'AbortError') {
            console.log('请求已被取消:', error.message);
        }
        // 取消请求时,不执行这里的代码
        const requestKey = generateRequestKey(error.config || {});
        pendingRequests.delete(requestKey);
        if (error.status) {
            return Promise.reject(error.response);
        }
    })
export default service

在接口封装层按照如上进行,可以满足接口重复请求时,取消重复的操作。需要注意一点,config.data,从request层获取的是Object,但是从response层获取的是一个JSON化的String。所以通过normalizeData方法,进行数据解析,防止map找不到。

相关推荐
IT_陈寒1 小时前
Python 3.12新特性实战:5个让你的代码提速30%的性能优化技巧
前端·人工智能·后端
sniper_fandc1 小时前
Vue Router路由
前端·javascript·vue.js
excel1 小时前
为什么 Vue 组件中的 data 必须是一个函数?(含 Vue2/3 对比)
前端
妄小闲2 小时前
成品网站模板源码 网站源码模板 html源码下载
前端·html
知识分享小能手10 小时前
微信小程序入门学习教程,从入门到精通,微信小程序常用API(上)——知识点详解 + 案例实战(4)
前端·javascript·学习·微信小程序·小程序·html5·微信开放平台
清灵xmf10 小时前
CSS field-sizing 让表单「活」起来
前端·css·field-sizing
文火冰糖的硅基工坊10 小时前
[光学原理与应用-480]:《国产检测设备对比表》
前端·人工智能·系统架构·制造·半导体·产业链
excel11 小时前
Qiankun 子应用生命周期及使用场景解析
前端
weixin_4462608511 小时前
Django - 让开发变得简单高效的Web框架
前端·数据库·django
ObjectX前端实验室12 小时前
【react18原理探究实践】异步可中断 & 时间分片
前端·react.js