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

一文解析axios源码

写了几年项目,也用了几年的axios,但是一直也不是很了解其中的原理,为啥他能请求前拦截,也为啥他能响应后拦截,正好有空,所以对他的源码进行分析,从github把他的源码拉下来进行分析:
在这里插入图片描述
从package.json可以看出主入口:index.js
在这里插入图片描述
查看/lib/axios.js
在这里插入图片描述

lib/axios.js 主要一个createInstance 创建一个实例的方法,我们使用axios的时候,都是这样使用的,如下面的代码所示,axios.create就是上面的方法创建的

// 创建axios实例
const service = axios.create({
    baseURL: '',
    timeout: 20000, // 请求超时时间
    headers: {
        'Content-Type': 'multipart/form-data'
    }
})

在继续看看new Axios里面干了啥,找到lib/core/Axios.js文件,分解来看,剔除了一些非核心代码,核心代码如下:

class Axios {
  constructor(instanceConfig) {
    this.defaults = instanceConfig;
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager()
    };

  async request(configOrUrl, config) {
    try {
      return await this._request(configOrUrl, config);
    } catch (err) 
    }
  }

  _request(configOrUrl, config) {
  

    const requestInterceptorChain = [];
    let synchronousRequestInterceptors = true;
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) 
      synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;

      requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    const responseInterceptorChain = [];
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    

      responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });

    let promise;
    let i = 0;
    let len;

    if (!synchronousRequestInterceptors) {
      const chain = [dispatchRequest.bind(this), undefined];
      chain.unshift.apply(chain, requestInterceptorChain);
      chain.push.apply(chain, responseInterceptorChain);
      len = chain.length;

      promise = Promise.resolve(config);

      while (i < len) {
        promise = promise.then(chain[i++], chain[i++]);
      }

      return promise;
    }

    len = requestInterceptorChain.length;

    let newConfig = config;

    i = 0;

    while (i < len) {
      const onFulfilled = requestInterceptorChain[i++];
      const onRejected = requestInterceptorChain[i++];
      try {
        newConfig = onFulfilled(newConfig);
      } catch (error) {
        onRejected.call(this, error);
        break;
      }
    }

    try {
      promise = dispatchRequest.call(this, newConfig);
    } catch (error) {
      return Promise.reject(error);
    }

    i = 0;
    len = responseInterceptorChain.length;

    while (i < len) {
      promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
    }

    return promise;
  }
}
// Provide aliases for supported request methods
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(mergeConfig(config || {}, {
      method,
      url,
      data: (config || {}).data
    }));
  };
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/

  function generateHTTPMethod(isForm) {
    return function httpMethod(url, data, config) {
      return this.request(mergeConfig(config || {}, {
        method,
        headers: isForm ? {
          'Content-Type': 'multipart/form-data'
        } : {},
        url,
        data
      }));
    };
  }

  Axios.prototype[method] = generateHTTPMethod();

  Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
});


核心步骤解析:
1、创建Axios类,构造函数中定义请求拦截和响应拦截

查看lib/core/InterceptorManager.js 文件new InterceptorManager(),主要是一个handlers数组,即

class Axios {
  constructor(instanceConfig) {
    this.defaults = instanceConfig;
    this.interceptors = {
      request: [],
      response:[]
    };
  } 
}

2、查看上述核心代码最后两段utils.forEach([‘delete’, ‘get’, ‘head’, ‘options’],即把这些都放到Axios.prototype[method]的原型上,当我们在使用axios.get的时候就是调用这里,而这里的方法其实就是调用this.request,而调用this.request则是调用_request方法
在这里插入图片描述

3、_request方法分析

_request(configOrUrl, config) {
    config = mergeConfig(this.defaults, config); // 默认config与传jinlaid的config进行合并
    // Set config.method
    config.method = (config.method || this.defaults.method || 'get').toLowerCase();// config的method优先从传进来的取,如果使用者没有传递,则使用默认config里面的method,默认的没有则默认get
    const requestInterceptorChain = [];
    let synchronousRequestInterceptors = true;
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    
      synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
	  
      requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    const responseInterceptorChain = [];
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
      responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });

    let promise;
    let i = 0;
    let len;

    if (!synchronousRequestInterceptors) {
      const chain = [dispatchRequest.bind(this), undefined];
      chain.unshift.apply(chain, requestInterceptorChain);
      chain.push.apply(chain, responseInterceptorChain);
      len = chain.length;

      promise = Promise.resolve(config);

      while (i < len) {
        promise = promise.then(chain[i++], chain[i++]);
      }

      return promise;
    }

    len = requestInterceptorChain.length;

    let newConfig = config;

    i = 0;

    while (i < len) {
      const onFulfilled = requestInterceptorChain[i++];
      const onRejected = requestInterceptorChain[i++];
      try {
        newConfig = onFulfilled(newConfig);
      } catch (error) {
        onRejected.call(this, error);
        break;
      }
    }

    try {
      promise = dispatchRequest.call(this, newConfig);
    } catch (error) {
      return Promise.reject(error);
    }

    i = 0;
    len = responseInterceptorChain.length;

    while (i < len) {
      promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
    }

    return promise;
  }

你可能有点懵,我们先来看看axios的请求拦截器和响应拦截器是怎么使用的,我们是不是都跟下面的代码一样使用的拦截器?

// 请求拦截器
service.interceptors.request.use(
    config => 
    },
    error => {
    }
)

// 响应拦截器
service.interceptors.response.use(
    response => 
    },
    error => {
       
    }
)

查看InterceptorManager.js代码,这里的use方法就是往handlers里面push
在这里插入图片描述
再看_request核心代码:先把this.interceptors.request请求拦截器数组里面全都用unshift放入到requestInterceptorChain数组里面,把this.interceptors.response响应拦截器数组里面的全部用push放入到responseInterceptorChain,然
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift.apply(chain, requestInterceptorChain);
chain.push.apply(chain, responseInterceptorChain);

请求拦截器+当前请求+响应拦截器的这是不是连接起来了? 这就是为什么在你发一个请求的时候,因为他是一条链,先zhi行请求拦截器,等所有的拦截器执行完,在执行当前请求,等你当前请求执行完再执行响应拦截器,全连起来了!

// filter out skipped interceptors
    const requestInterceptorChain = [];
    let synchronousRequestInterceptors = true;
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
      if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
        return;
      }

      synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;

      requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    const responseInterceptorChain = [];
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
      responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });
    
	const chain = [dispatchRequest.bind(this), undefined];
     chain.unshift.apply(chain, requestInterceptorChain);
     chain.push.apply(chain, responseInterceptorChain);
     len = chain.length;

     promise = Promise.resolve(config);

     while (i < len) {
       promise = promise.then(chain[i++], chain[i++]);
     }

     return promise;

dispatchRequest则是调用请求的一个方法,其实就是XMLHttpRequest那一套,做了一个适配器的封装,暂不叙述!

所以综合起来看axios就是一个请求接口的一个封装插件,,提供很多方法让你去使用


http://www.kler.cn/a/376547.html

相关文章:

  • Spring Cloud Ribbon:负载均衡的服务调用
  • 【机器学习】回归树
  • RabbitMQ最全教程-Part1(基础使用)
  • 实体类中为什么要实现serializable接口
  • WebGPU跨平台应用开发
  • 【Git】Git常用命令
  • uniapp MD5加密
  • 网络请求优化:理论与实践
  • Oracle视频基础1.3.7练习
  • 【python】爬虫
  • APISQL企业版离线部署教程
  • 二叉苹果树
  • Redis主从复制:全量复制与增量复制区别与联系
  • scala---10.30
  • 《Python爬虫:价格侦探的奇妙冒险》
  • 「C/C++」C/C++ 之 循环结构详解
  • volatile变量
  • Vue2——单页应用程序路由的使用
  • SpringBoot实现国密通信
  • 基于MATLAB驾驶行为的疲劳实时检测研究
  • android数组控件Textview
  • sublime Text中设置编码为GBK
  • 电子时钟--html+css+js实现
  • 【热门主题】000011 React前沿:构建高效与灵动的现代Web应用
  • 分布式事务-SpringBoot集成Seata
  • Mybatis学习笔记(二)