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

    正文概述 掘金(lain_lee)   2021-02-20   668

    引言

    熟悉 Vue 的同学们,肯定都用过 Axios , 简洁的 API 语法和方便的拦截器都受到了开发者的热烈欢迎,使用背后,是否也想了解一下实现原理呢,其实源码并不难阅读,这里我就抛砖引玉,对源码做一个浅析

    回顾

    首先我们回顾一下常用的 Axios 功能都有哪些

    • axios(config) / axios.get / axios.post / axios.delete ....

      调用 axios ,传参发起一个请求,或者直接发起 get、post、delete 等请求

    • axios.create

      创建一个新的 axios 实例

    • axios.defaults.xxxx

      配置 axios 的默认配置

    • axios.interceptors.request / axios.interceptors.response

      配置 axios 的全局拦截器,也可以只配置某个通过 create 创建的实例的拦截器

    • cancel

      取消某个请求

    接下来我们根据源码一一解析,上述的功能是如何实现的

    代码结构

    源代码里的主要目录是 lib ,其余的是一些单元测试、文档之类的,这里不再赘述

    lib
    │  axios.js
    │  defaults.js
    │  utils.js
    │
    ├─adapters
    │      http.js
    │      README.md
    │      xhr.js
    │
    ├─cancel
    │      Cancel.js
    │      CancelToken.js
    │      isCancel.js
    │
    ├─core
    │      Axios.js
    │      buildFullPath.js
    │      createError.js
    │      dispatchRequest.js
    │      enhanceError.js
    │      InterceptorManager.js
    │      mergeConfig.js
    │      README.md
    │      settle.js
    │      transformData.js
    │
    └─helpers
            bind.js
            buildURL.js
            combineURLs.js
            cookies.js
            deprecatedMethod.js
            isAbsoluteURL.js
            isAxiosError.js
            isURLSameOrigin.js
            normalizeHeaderName.js
            parseHeaders.js
            README.md
            spread.js
    

    这里有几个重要文件(axios.js、defaults.js、utils.js)以及几类文件分别放在四个文件夹里

    • axios.js

      该文件作为入口文件,主要作为生成并导出 axios 对象、以及扩展一系列例如 axios.create 的功能方法

    • defaults.js

      该文件是默认配置

    • utils.js

      该文件是一系列辅助方法,例如:isStirng、extend 等等

    • adapter

      该目录里主要存放一些与 ajax 的适配器,也就是封装原生的 xmlHttpRequest 或者 node 的 http 库等,然后处理成方便使用的自己的方法,如果以后有更新的 ajax 方法,例如 fetch,那么 Axios 只需要修改这部分去适配新的接口即可

    • cancel

      这里实现取消请求的功能

    • core

      这是 Axios 的核心代码,包括 Axios 的基类、一些错误的封装等等,其中比较核心的又有 Axios.js、dispatchRequest.js、InterceptorManager.js

    • helpers

      这里另一部分辅助的功能性模块,和 utils.js 的区别可能是因为 utils.js 是更加通用的方法,而这个目录里的则是定制的一些辅助方法

    源码分析

    axios(config) / axios.get / axios.create 等方法实现

    我们暂时先不关心具体的实现,首先来看如何将抽象方法暴露出来提供开发者使用,这里主要关注 lib/axios.js 这个文件

    // path: lib/axios.js
    
    var utils = require('./utils');
    var bind = require('./helpers/bind');
    var Axios = require('./core/Axios');
    var mergeConfig = require('./core/mergeConfig');
    var defaults = require('./defaults');
    
    function createInstance(defaultConfig) {
      var context = new Axios(defaultConfig);
      var instance = bind(Axios.prototype.request, context);
    
      // Copy axios.prototype to instance
      utils.extend(instance, Axios.prototype, context);
    
      // Copy context to instance
      utils.extend(instance, context);
    
      return instance;
    }
    
    // Create the default instance to be exported
    var axios = createInstance(defaults);
    
    // Factory for creating new instances
    axios.create = function create(instanceConfig) {
      return createInstance(mergeConfig(axios.defaults, instanceConfig));
    };
    
    axios.Cancel = ...
    axios.CancelToken = ...
    axios.isCancel = ...
    axios.all = ...
    axios.spread = ...
    axios.isAxiosError = ...
    
    module.exports = axios;
    

    可以看出,我们开发者使用的 axios,也是通过 Axios 基类生成的一个实例(严格意义上说并不是一个单纯的实例)

    可能有的同学要问了,为何不直接 export 一个实例呢,还封装一个函数,有什么用意呢,其实这里的目的是在导出实例的同时,将我们标题上说的 axios(config) / axios.get / axios.create 等方法也绑定上去,扩展这个实例,使它的功能更强大,我们接下来一步步看是怎么实现的:

    • var context = new Axios(defaultConfig);
      var instance = bind(Axios.prototype.request, context);
      

      这两行先是生成一个实例 context,然后通过 bind 函数将基类 Axiosrequest 方法的上下文 this 绑定为实例 context,并生成一个新的方法 instance,也就是未来我们用的 axios 对象,到这一步,axios 对象本质上还只是一个 request 方法

    • utils.extend(instance, Axios.prototype, context);
      

      这一步,通过 extend 方法,将 Axios.prototype ,也就是基类的原型链,合并(继承)到 instancerequest) 对象上,这之中当然是冗余的,也就是 instance 的原型上也包含自身 request 方法,到这里就实现了 axios(config)(相当于 axios.request(config))以及 axios.get / axios.post ... (原型链方法)这几个功能

    • utils.extend(instance, context)
      

      这一步,还是通过 extend 方法,将 context(实例)的其他属性,例如:defaults、interceptors 合并到 instance 对象上

    • axios.create = function create(instanceConfig) {
        return createInstance(mergeConfig(axios.defaults, instanceConfig));
      };
      

      这里将 createInstance 函数扩展为 axios.create ,允许开发者生成新的实例,同样的,也扩展了 Cancelall 等方法

    最后,我们得到了一个对象 axios ,它看起来像 Axios 类的实例,用起来也像实例,然而它只是一个 request 方法,但是拥有实例的属性和原型,以及一些其他的 API

    axios 的默认配置

    接下来我们在深入具体逻辑之前,先看一下,Axios 都有什么默认配置,如何实现修改全局配置,以及区分实例的配置

    再回看一下上面的代码以及 Axios 基类

    // lib/core/Axios.js
    function Axios(instanceConfig) {
      this.defaults = instanceConfig;
      this.interceptors = {
        request: new InterceptorManager(),
        response: new InterceptorManager()
      };
    }
    
    // lib/axios.js
    var defaults = require('./defaults');
    // Create the default instance to be exported
    var axios = createInstance(defaults);
    
    // Factory for creating new instances
    axios.create = function create(instanceConfig) {
      return createInstance(mergeConfig(axios.defaults, instanceConfig));
    };
    

    全局配置是一个文件,通过 new 一个实例,绑定到 axios 对象上的 defaults 属性上,而之后通过 axios.create 创建的实例,都要和 axios.defaults 合并之后再实例化,因此,axios.defaluts 就变成了一个全局配置,修改该属性会影响 axios 对象以及通过它派生出来的所有实例,而实例上有自己的 defaults 对象,修改它只会影响自己

    接下来我们看一下具体的默认配置都有哪些

    var DEFAULT_CONTENT_TYPE = {
      'Content-Type': 'application/x-www-form-urlencoded'
    };
    
    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;
    }
    
    var defaults = {
      adapter: getDefaultAdapter(),
      transformRequest: [...],
      transformResponse: [...],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      validateStatus: function validateStatus(status) {
        return status >= 200 && status < 300;
      }
    };
    defaults.headers = {
      common: {
        'Accept': 'application/json, text/plain, */*'
      }
    };
    utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
      defaults.headers[method] = {};
    });
    utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
      defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
    });
    module.exports = defaults;
    

    这里省略了一些细节,具体可以去源代码里查看,但是看到这里是不是很多同学反应过来了,原来文档里说的根本不是默认配置,只是列举了一下所有可用的配置以及应该传什么值,而真正的默认配置只有上面文件里的这些

    • adapter

      这里区分了浏览器环境还是 Node 环境,这里分别匹配了 lib/adapters/xhr.js 和 lib/adapters/http.js 文件,也允许开发者自己做适配,反正我还没有适配过...

    • transformRequest 和 transformResponse

      这里都有默认配置,判断分支还挺多,如果修改配置的话,直接赋值,这些逻辑就都没了,个人感觉这里设计的不是很好,所以如果只是想增加新的 transform 规则的话,我建议在默认的基础上新增:

      axios.defaults.transformRequest = [ ...axios.defaults.transformRequest, ...customerTransform ]

    • timeout、xsrfCookieName、xsrfHeaderName、maxContentLength、maxBodyLength、validateStatus

      这些配置都很容易理解,这里不赘述

    • headers

      默认的 header 头,有一个通用 Accept 头,然后具体区分了一下请求类型,只有 'post', 'put', 'patch' 这三种请求会带上默认的 'Content-Type': 'application/x-www-form-urlencoded'看清楚了啊,可不是 'application/json' (狗头)

    总结

    第一部分暂时就写到这里,主要介绍了 Axios 的实例和默认配置以及,其实源码并不复杂,只是做了比较详细的功能拆分,接下来第二部分我会深入 request 请求的核心,以及拦截器的实现,作为搬砖人,能力有限,如果有童鞋对这一部分的哪里还没有看懂,觉得我没有描述清楚的,可以在留言区讨论


    起源地下载网 » Axios 源码浅析(一)—— Axios 实例及配置

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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