axios 源码分析(发起请求流程)

本文详细解析了Axios库的内部工作流程,包括如何通过`bind()`创建实例,请求和响应拦截器的使用,以及`dispatchRequest`在其中的作用。Axios实例通过原型链继承了各种请求方法,并利用Promise串联起请求拦截器、实际请求和响应拦截器,形成完整的请求处理链。此外,还介绍了默认配置、请求转换器和响应转换器的功能,确保数据的正确格式化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

axios.js与Axios.js息息相关,Axios.js调用了request方法,request方法又分别调用了InterceptorManager.js和dispatchRequest,dispatchRequest又调用了adapter,adapter中new了一个xhr实例。defaults.js是默认的配置文件。

Axios

axios是入口文件,是一个函数,所以它不是Axios的实例,但是axios具有Axios原型链的所有方法,具有Axios实例应该具有的属性。
axios是Axios.prototype.request函数bind()返回的函数。

axios.js

function createInstance(defaultConfig) {
  /* 
  创建Axios的实例
      原型对象上有一些用来发请求的方法: get()/post()/put()/delete()/request()
      自身上有2个重要属性: defaults/interceptors
  */  
  var context = new Axios(defaultConfig);

  // axios和axios.create()对应的就是request函数
  // Axios.prototype.request.bind(context)
  var instance = bind(Axios.prototype.request, context); // axios

  // 将Axios原型对象上的方法拷贝到instance上: request()/get()/post()/put()/delete()
  utils.extend(instance, Axios.prototype, context); 

  // 将Axios实例对象上的属性拷贝到instance上: defaults和interceptors属性
  utils.extend(instance, context);

  return instance;
}

// Create the default instance to be exported
var axios = createInstance(defaults);

Axios
原型上的属性

function Axios(instanceConfig) {
  // 将指定的config, 保存为defaults属性
  this.defaults = instanceConfig;
  // 将包含请求/响应拦截器管理器的对象保存为interceptors属性
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}

原型上的request

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);
  // 添加method配置, 默认为get
  config.method = config.method ? config.method.toLowerCase() : 'get';

  /*
  创建用于保存请求/响应拦截函数的数组
  数组的中间放发送请求的函数
  数组的左边放请求拦截器函数(成功/失败)
  数组的右边放响应拦截器函数
  */
  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);
  });
  

  // 通过promise的then()串连起所有的请求拦截器/请求方法/响应拦截器
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }

  // 返回用来指定我们的onResolved和onRejected的promise
  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(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});
//给元原型对象添加方法名字
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

流程:Axios中定义了request,get,等各种基本方法,制定了默认属性添加了拦截器,axios通过bind成为指向Axios实例,并有request方法的新函数。后又通过集成,继承了Axios原型链上的方法和属性,至此成为一个具有Axios原型链的所有方法,具有Axios实例应该具有的属性的函数。最后又添加了其他方法,例:create,all等。

请求响应拦截器与dispatchRequest串联[request(config)]负责链接整个流程

/*
  创建用于保存请求/响应拦截函数的数组
  数组的中间放发送请求的函数
  数组的左边放请求拦截器函数(成功/失败)
  数组的右边放响应拦截器函数
  */
  var chain = [dispatchRequest, undefined]; //undefined是有用的,因为promise.then()取出两个
  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);
  });
  

  // 通过promise的then()串连起所有的请求拦截器/请求方法/响应拦截器
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }

  // 返回用来指定我们的onResolved和onRejected的promise
  return promise;

request通过promise的then()将请求拦截器发起请求,响应拦截器,以及我自己发起的成功/失败的回调(dispatchRequest())串联起来,返回promise。请求拦截器先添加后执行,因为通过数组的unshift方法

dispatchRequest(config)负责转换请求和响应数据

转换请求数据,调用xhrAdapter()发请求,请求返回后转换响应数据,返回promise。
请求拦截器负责将data转换成json格式以及更改请求头
响应拦截器负责将响应数据从json格式转换为对象,如果不是json格式则不做处理

请求转换器

transformRequest: [function transformRequest(data, headers) {
    // 指定headers中更规范的请求头属性名
    normalizeHeaderName(headers, 'Accept');
    normalizeHeaderName(headers, 'Content-Type');


    if (utils.isFormData(data) ||
      utils.isArrayBuffer(data) ||
      utils.isBuffer(data) ||
      utils.isStream(data) ||
      utils.isFile(data) ||
      utils.isBlob(data)
    ) {
      return data;
    }
    if (utils.isArrayBufferView(data)) {
      return data.buffer;
    }
    if (utils.isURLSearchParams(data)) {
      setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
      return data.toString();
    }
    // 如果data是对象, 指定请求体参数格式为json, 并将参数数据对象转换为json
    if (utils.isObject(data)) {
      setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
      return JSON.stringify(data);
    }
    return data;
  }],

响应转换器

  // 响应数据转换器: 解析字符串类型的data数据
  transformResponse: [function transformResponse(data) {
    /*eslint no-param-reassign:0*/
    if (typeof data === 'string') {
      try {
        data = JSON.parse(data);
      } catch (e) { /* Ignore */ }
    }
    return data;
  }],

xhrAdapter(config)发起请求

创建XHR对象,根据config进行响应设置,发送特定请求,并接收响应数据,返回promise。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值