最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Axios 源码分析

    正文概述 掘金(今天早起不秃头)   2021-02-07   513

    说明

    axios 是基于 promise 的http库,可以用在浏览器和node.js 中来处理网络请求。

    axios的特点有

    • 从浏览器中创建 XMLHttpRequests
    • 从 node.js 创建 http 请求
    • 支持 Promise API
    • 拦截请求和响应
    • 转换请求数据和响应数据
    • 取消请求
    • 自动转换 JSON 数据
    • 客户端支持防御 [XSRF]

    在一些通用配置上,可以指定默认配置

    axios.defaults.baseURL = 'https://api.example.com';
    axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    

    axios.js 入口文件

    axios是源码中已经创建好的一个实例,用 axios.js 中的createInstance函数来创建。此外axios实例上挂载了许多方法

    • 当有许多基于不同配置的请求时,可以利用 axios.create 创建一个新的 axios实例。

      // 创建实例时设置配置的默认值
      var instance = axios.create({
        baseURL: 'https://api.example.com'
      });
        
      // 在实例已创建后修改默认值
      instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
      

    createInstance 函数:

    • new 了一个 Axios 实例 context
    • 将 Axios.prototype.request 的 this 指向 context
    • 将Axios.prototype 中的方法赋给 instance,并将 instance 的this指向 context
    • 将 context 上的方法 赋给 instance
    function createInstance(defaultConfig) {
      var context = new Axios(defaultConfig);
      var instance = bind(Axios.prototype.request, context);
      // module.exports = function bind(fn, thisArg) {
      //   return function wrap() {
      //     var args = new Array(arguments.length);
      //     for (var i = 0; i < args.length; i++) {
      //       args[i] = arguments[i];
      //     }
      //     return fn.apply(thisArg, args);
      //   };
      // };
    
      // Copy axios.prototype to instance
      utils.extend(instance, Axios.prototype, context);
      // function extend(a, b, thisArg) {
      //   forEach(b, function assignValue(val, key) {
      //     if (thisArg && typeof val === 'function') {
      //       a[key] = bind(val, thisArg);
      //     } else {
      //       a[key] = val;
      //     }
      //   });
      //   return a;
      // }
    
      // Copy context to instance
      utils.extend(instance, context);
    
      return instance;
    }
    

    axios.all 其实就是 Promise.all

    axios.all = function all(promises) {
      return Promise.all(promises);
    };
    

    Axios.js

    Axios.js 中的 axios.prototype.request 是axios 的核心函数。

    • 首先将 传入的配置参数与默认的配置 合并
    • 然后设置 config 的 method并将method转换成小写字母
    • 创建了一个 chain并传入 两个参数:dispathRequest 和 undefined
    • 将config用 promise包装
    • 将请求拦截器中注册的 中间件 从chain的头部一次插入两个,将响应拦截器中注册的中间件从chain的尾部一次插入两个
    • 然后一次从 chain中取出两个参数,先执行 request请求,然后到 dispathchRequest, 再执行 response 响应
    • 最后返回 promise
    Axios.prototype.request = function request(config) {
      /*eslint no-param-reassign:0*/
      // Allow for axios('example/url'[, config]) a la fetch API
      if (typeof config === 'string') {
        config = arguments[1] || {};
        config.url = arguments[0];
      } else {
        config = config || {};
      }
    
      config = mergeConfig(this.defaults, config);
    
      // Set config.method
      if (config.method) {
        config.method = config.method.toLowerCase();
      } else if (this.defaults.method) {
        config.method = this.defaults.method.toLowerCase();
      } else {
        config.method = 'get';
      }
    
      // Hook up interceptors middleware
      var chain = [dispatchRequest, undefined];
      var promise = Promise.resolve(config);
    
      this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        chain.unshift(interceptor.fulfilled, interceptor.rejected);
      });
    
      this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        chain.push(interceptor.fulfilled, interceptor.rejected);
      });
    
      while (chain.length) {
        promise = promise.then(chain.shift(), chain.shift());
      }
    
      return promise;
    };
    
    • 拦截器是一个数组

      function Axios(instanceConfig) {
        this.defaults = instanceConfig;
        this.interceptors = {
          request: new InterceptorManager(),
          response: new InterceptorManager()
        };
      }
        
      function InterceptorManager() {
        this.handlers = [];
      }
      
    • use就是将参数push进拦截器数组,一次必须传入两个参数

    InterceptorManager.prototype.use = function use(fulfilled, rejected) {
      this.handlers.push({
        fulfilled: fulfilled,
        rejected: rejected
      });
      return this.handlers.length - 1;
    };
    

    dispatchRequest.js

    dispatchRequest 是 Axios.prototype.request 调用的处理 axios 发起请求的参数:

    • 首先判断请求是否取消

    • 如果没有取消,用 transformData 将请求数据进行转换

    • 利用utils.merge 将 config.headers.common || {}, config.headers[config.method] || {},config.headers 进行合并

    • 删除多余的请求头

    • 初始化一个适配器,如果当前环境是浏览器就是用 xhr 适配器,如果是node环境,就使用http适配器。

      function getDefaultAdapter() {
        var adapter;
        if (typeof XMLHttpRequest !== 'undefined') {
          // For browsers use XHR adapter
          adapter = require('./adapters/xhr');
        } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
          // For node use HTTP adapter
          adapter = require('./adapters/http');
        }
        return adapter;
      }
      
    • 执行适配器,返回用promise包装的 response,将 response 数据转换成如下格式

      reason.response.data,
      reason.response.headers,
      config.transformResponse
      
    module.exports = function dispatchRequest(config) {
      throwIfCancellationRequested(config);
    
      // Ensure headers exist
      config.headers = config.headers || {};
    
      // Transform request data
      config.data = transformData(
        config.data,
        config.headers,
        config.transformRequest
      );
    
      // Flatten headers
      config.headers = utils.merge(
        config.headers.common || {},
        config.headers[config.method] || {},
        config.headers
      );
    
      utils.forEach(
        ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
        function cleanHeaderConfig(method) {
          delete config.headers[method];
        }
      );
    
      var adapter = config.adapter || defaults.adapter;
    
      return adapter(config).then(function onAdapterResolution(response) {
        throwIfCancellationRequested(config);
    
        // Transform response data
        response.data = transformData(
          response.data,
          response.headers,
          config.transformResponse
        );
    
        return response;
      }, function onAdapterRejection(reason) {
        if (!isCancel(reason)) {
          throwIfCancellationRequested(config);
    
          // Transform response data
          if (reason && reason.response) {
            reason.response.data = transformData(
              reason.response.data,
              reason.response.headers,
              config.transformResponse
            );
          }
        }
    
        return Promise.reject(reason);
      });
    };
    
    
    

    起源地 » Axios 源码分析

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元