傲渊山岳 发表于 2025-4-4 00:31:36

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

处置惩罚网络哀求时,我们常常会遇到必要中途取消哀求的环境,比如用户在两个tab之间反复横跳的场景,假如每个接口都从头哀求到结束,那一定会造成很大的服务压力。
AbortController是一个Web API,它提供了一个信号对象(AbortSignal),该对象可以用来取消与Fetch API相干的操作。当我们创建AbortController实例时,会主动生成一个与之关联的AbortSignal对象。我们可以将这个AbortSignal对象作为参数转达给fetch函数,从而实现对网络哀求的取消控制。
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) {
            //result0-正常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找不到。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【接口重复哀求】axios通过AbortController解决页面切换过快,接口重复哀求问题