【axios】的浅度分析

一、Axios的拦截器能干些什么?

Axios拦截器的实现原理主要涉及两个方面:请求拦截器和响应拦截器,它们分别在请求发送前和响应返回后进行预处理和后处理。

Axios内部维护了两个数组,一个用于存储请求拦截器,另一个用于存储响应拦截器。每个拦截器都是一个函数,这些函数按照它们在数组中定义的顺序被依次执行。

1、请求拦截器:

当Axios发起一个请求时,会首先遍历并执行请求拦截器数组中的每个函数。

请求拦截器的作用是在请求发送前对请求进行修改或添加一些公共的逻辑,例如给每个请求体都加上token,或者修改请求的配置,如headers、url、params等。此外,也可以在此阶段取消请求。

请求拦截器的修改或添加的配置将被用于之后的请求发送。

2、响应拦截器:

一旦请求被发送并得到响应,Axios会遍历并执行响应拦截器数组中的每个函数。

响应拦截器的作用是在响应返回后对响应进行特定的处理,例如对返回的数据进行统一处理或对特定的错误进行处理。

如果响应是一个正常的响应,可以直接返回数据或对数据进行修改。如果响应是一个错误(例如,404或500状态码),可以进行错误处理或重试逻辑。

使用Axios拦截器的好处包括统一处理公共逻辑,减少重复代码,提高代码的可读性和可维护性。同时,也可以在请求或响应不符合预期时进行统一处理,提高程序的健壮性。

需要注意的是,在使用Axios拦截器时,应确保请求拦截器在响应拦截器之前执行,避免逻辑上的错误。此外,应避免在拦截器中修改原始请求或响应数据,以免影响其他拦截器或请求处理器的处理结果。同时,应考虑性能问题,避免在拦截器中进行耗时的操作。

综上所述,Axios拦截器的实现原理主要基于其内部维护的请求和响应拦截器数组,通过依次执行这些拦截器函数,实现对请求和响应的预处理和后处理。

二、Axios 源码中,拦截器是怎么实现的?(最简化的理解)

Axios 的拦截器实现基于 Axios 的核心原理,即 Axios 实例是一个包含请求和响应拦截器堆栈的对象。当发出请求或接收响应时,Axios 会遍历这些拦截器,并按照添加的顺序执行请求拦截器,以及按照相反的顺序执行响应拦截器。

在 Axios 的源码中,拦截器是通过一个 AxiosInterceptorManager 实例来管理的,它维护了一个拦截器数组。每个拦截器都是一个包含 fulfilledrejected 函数的对象。这两个函数分别对应于拦截器成功处理和拦截器处理出错的情况。

以下是 Axios 拦截器管理器的一个简化版本,展示了其核心实现思路:

javascript 复制代码
class InterceptorManager {
  constructor() {
    this.handlers = []; // 存储拦截器的数组
  }

  use(fulfilled, rejected) {
    this.handlers.push({
      fulfilled: fulfilled,
      rejected: rejected
    });
    return this.handlers.length - 1; // 返回拦截器的ID
  }

  eject(id) {
    if (this.handlers[id]) {
      this.handlers[id] = null; // 移除拦截器
    }
  }

  forEach(fn) {
    this.handlers.forEach((h) => {
      if (h !== null) {
        fn(h);
      }
    });
  }
}

在发送请求或接收响应时,Axios 会创建一个 promise 链,并通过 forEach 方法将拦截器中的 fulfilledrejected 函数添加到这个链中。这样,每个拦截器都可以对请求或响应进行处理,然后将结果传递到链的下一个拦截器,或者在出错时结束链的执行。
PS:注意,上面说的是拦截管理器,并非下面要说的拦截器

javascript 复制代码
axios.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
  chain.unshift(interceptor.fulfilled, interceptor.rejected);
});

axios.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
  chain.push(interceptor.fulfilled, interceptor.rejected);
});

在 Axios 的完整实现中,这个拦截器机制被集成到了 Axios 的请求发送和响应处理流程中。通过这种方式,Axios 可以在发送请求之前和接收响应之后,但在用户定义的 .then.catch 执行之前,插入自定义的逻辑。

请注意,这里提供的代码只是为了说明 Axios 拦截器的实现原理,并不是 Axios 源码的完整复制。

三、高度简化的源码(axios拦截器实现源码)

Axios 拦截器的实现源码涉及到其核心模块的设计。Axios 允许你注册请求拦截器和响应拦截器,这些拦截器在请求发送前和响应返回后进行相应的处理。以下是简化的 Axios 拦截器实现源码的概述:

javascript 复制代码
// 假设 Axios 实例有一个 interceptors 对象,其中包含了 request 和 response 两个数组
const instance = {
  interceptors: {
    request: [],
    response: []
  }
};

// 请求拦截器的函数定义
function onFulfilled(fulfilled, rejected) {
  return function (config) {
    return new Promise((resolve, reject) => {
      try {
        const result = fulfilled(config);
        if (result && typeof result.then === 'function') {
          result.then(resolvedConfig => {
            resolve(resolvedConfig);
          }, rejected);
        } else {
          resolve(result);
        }
      } catch (error) {
        reject(error);
      }
    };
  };
}

// 响应拦截器的函数定义
function onFulfilledResponse(fulfilled, rejected) {
  return function (response) {
    return new Promise((resolve, reject) => {
      try {
        const result = fulfilled(response);
        if (result && typeof result.then === 'function') {
          result.then(resolvedResponse => {
            resolve(resolvedResponse);
          }, rejected);
        } else {
          resolve(result);
        }
      } catch (error) {
        reject(error);
      }
    };
  };
}

// 添加请求拦截器
instance.interceptors.request.use = function (fulfilled, rejected) {
  this.interceptors.request.push({
    fulfilled: onFulfilled(fulfilled, rejected),
    rejected: rejected
  });
  return this;
};

// 添加响应拦截器
instance.interceptors.response.use = function (fulfilled, rejected) {
  this.interceptors.response.push({
    fulfilled: onFulfilledResponse(fulfilled, rejected),
    rejected: rejected
  });
  return this;
};

// 简化版的请求发送函数,用于展示拦截器如何处理
function dispatchRequest(config) {
  return new Promise((resolve, reject) => {
    // 遍历并执行请求拦截器
    const chain = [Promise.resolve(config)];
    instance.interceptors.request.forEach(interceptor => {
      chain.unshift(interceptor.fulfilled, interceptor.rejected);
    });
    // 遍历并执行响应拦截器
    chain.push(dispatchRequestToServer); // 假设这个函数是实际发送请求到服务器的函数
    while (chain.length) {
      const currentInterceptor = chain.shift();
      const nextInterceptor = chain.shift();
      if (typeof currentInterceptor === 'function') {
        currentInterceptor(config).then(chain => {
          if (typeof nextInterceptor === 'function') {
            nextInterceptor(chain);
          } else {
            resolve(chain);
          }
        }).catch(reject);
      }
    }
  });
}

// 假设函数,用于实际发送请求到服务器
function dispatchRequestToServer(config) {
  // 这里应该是实际的请求发送逻辑,为了简化,我们直接返回一个模拟的响应
  return Promise.resolve({
    data: 'Response data'
  });
}

// 使用拦截器
instance.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    console.log('Request interceptor called', config);
    // 可以在这里修改config对象
    return config;
  },
  error => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

instance.interceptors.response.use(
  response => {
    // 对响应数据做点什么
    console.log('Response interceptor called', response);
    // 可以在这里修改响应数据
    return response;
  },
  error => {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

// 发送请求
dispatchRequest({ url: 'https://api.example.com/data' })
  .then(response => {
    console.log('Response received:', response);
  })
  .catch(error => {
    console.error('Error occurred:', error);
  });

以上代码是一个高度简化的版本,用于展示 Axios 拦截器是如何实现的。如果你对 Axios 的拦截器实现细节感兴趣,建议查看 Axios 的官方 GitHub 仓库中的源码。

相关推荐
陈王卜2 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
景天科技苑9 分钟前
【vue3+vite】新一代vue脚手架工具vite,助力前端开发更快捷更高效
前端·javascript·vue.js·vite·vue项目·脚手架工具
石小石Orz18 分钟前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
小行星12521 分钟前
前端预览pdf文件流
前端·javascript·vue.js
join822 分钟前
解决vue-pdf的签章不显示问题
javascript·vue.js·pdf
小行星12527 分钟前
前端把dom页面转为pdf文件下载和弹窗预览
前端·javascript·vue.js·pdf
Lysun00137 分钟前
[less] Operation on an invalid type
前端·vue·less·sass·scss
土豆湿43 分钟前
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
开发语言·javascript·css
J总裁的小芒果1 小时前
Vue3 el-table 默认选中 传入的数组
前端·javascript·elementui·typescript
Lei_zhen961 小时前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron