发送请求

dispatchRequest是axios的发送请求部分。
它会根据环境调用请求适配器,如果是浏览器环境,调用xhr来发送请求,如果是nodejs环境,调用http发送请求。
封装好的适配器都会返回一个promise,所以在dispatchRequest中会对适配器调用then方法,传递fulfilled和rejected,然后then方法会返回promise,让then链后面的操作能够继续执行下去。
下面是dispatchRequest源代码:
'use strict';

var utils = require('./../utils');
var transformData = require('./transformData');
var isCancel = require('../cancel/isCancel');
var defaults = require('../defaults');
var isAbsoluteURL = require('./../helpers/isAbsoluteURL');
var combineURLs = require('./../helpers/combineURLs');

/**
 * Throws a `Cancel` if cancellation has been requested.
 */
//抛出Cancel错误,如果取消操作已经被请求
function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    //如果请求配置传递了cancelToken属性,就调用cancelToken对象上的throwIfRequested方法判断cancelToken对象上的reason属性有没有生成,如果生成了就立即抛出cancel对象的错误取消掉当前请求
    config.cancelToken.throwIfRequested();
  }
}

/**
 * Dispatch a request to the server using the configured adapter.
 *
 * @param {object} config The config that is to be used for the request
 * @returns {Promise} The Promise to be fulfilled
 */
//向服务器发出请求,使用配置好的adapter(适配器,负责发送http请求的核心代码)
module.exports = function dispatchRequest(config) {
  throwIfCancellationRequested(config);
  //如果传递了cancelToken配置,并且已经调用了取消操作,就抛出cancel将请求取消

  // Support baseURL config
  //如果配置里面传递了baseURL项,并且config.url是相对路径
  //那么就将config.baseURL, config.url连接起来形成真正的路径
  if (config.baseURL && !isAbsoluteURL(config.url)) {
    config.url = combineURLs(config.baseURL, config.url);
  }

  // Ensure headers exist
  //保证配置里的headers属性存在,如果没有传递就赋值为一个空对象
  config.headers = config.headers || {};

  // Transform request data
  //在请求发送之前改变数据data
  config.data = transformData(
    config.data,
    config.headers,
    config.transformRequest
  );

  // Flatten headers
  //将headers对象里的common属性,method名对应的属性展开
  //common属性指的是对所有类型请求都需要添加的请求头,而method名对应的属性是指定类型请求需要添加的请求头
  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;
  //请求的适配器(适配器,负责发送http请求的核心代码),如果用户传递了自定义adapter就用自定义的,否则使用默认adapter

  return adapter(config).then(function onAdapterResolution(response) {//adapter的promise成功后执行的方法
    throwIfCancellationRequested(config);
    //如果传递了cancelToken配置,并且已经调用了取消操作,就抛出cancel将请求取消

    // Transform response data
    //在响应数据生成之前改变响应数据data
    response.data = transformData(
      response.data,
      response.headers,
      config.transformResponse
    );

    return response;//返回响应responses 
  }, function onAdapterRejection(reason) {//adapter的promise失败后执行的方法
    if (!isCancel(reason)) {//判断错误时的reason是不是Cancel对象
      throwIfCancellationRequested(config);//抛出Cancel错误,如果取消操作已经被请求

      // Transform response data
      if (reason && reason.response) {//如果resaon.response存在,在请求返回响应前改变它
        reason.response.data = transformData(
          reason.response.data,
          reason.response.headers,
          config.transformResponse
        );
      }
    }

    return Promise.reject(reason);//将结果返回,通过一个reject的promise
  });
};

dispatchRequest方法中不只发送了请求,还在请求之前和响应之后调用transformData方法来处理请求之前的数据和响应之后的数据。

用户传入的config里面有transformRequest和transformResponse这两个配置项数组,它们可以传入多个处理函数,接收data和headers,参数和请求或响应头部来做自定义处理。
下面是transformData源代码
'use strict';

var utils = require('./../utils');

/**
 * Transform the data for a request or a response
 *
 * @param {Object|String} data The data to be transformed
 * @param {Array} headers The headers for the request or response
 * @param {Array|Function} fns A single function or Array of functions
 * @returns {*} The resulting transformed data
 */
//改变请求或者响应的数据
//配置里transformRequest属性和transformResponse属性负责改变,也就是transformData方法的第三个参数fns
//transformRequest,在数据发送给服务器之前对其作出修改
//transformResponse,在响应数据被生成固定格式之前对其作出修改
module.exports = function transformData(data, headers, fns) {
  /*eslint no-param-reassign:0*/
  utils.forEach(fns, function transform(fn) {
    //调用forEach循环fns数组,传入配置项data和headers调用每一个fn
    data = fn(data, headers);
  });

  return data;//返回最终被改变后的data
};

下面是isAbsoluteURL源码:

'use strict';

/**
 * Determines whether the specified URL is absolute
 *
 * @param {string} url The URL to test
 * @returns {boolean} True if the specified URL is absolute, otherwise false
 */
//检查url是否是绝对路径
module.exports = function isAbsoluteURL(url) {
  // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
  // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
  // by any combination of letters, digits, plus, period, or hyphen.
  //一个绝对url会以<scheme>://开头或者//开头(相对协议)
  //RFC 3986定义scheme名是一个字符序列,以一个字母开头,后跟字母,数组,加号,点号或者连字符的任何连接形式
  return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
};

下面是combineURLs源码:

'use strict';

/**
 * Creates a new URL by combining the specified URLs
 *
 * @param {string} baseURL The base URL
 * @param {string} relativeURL The relative URL
 * @returns {string} The combined URL
 */
//连接指定的url创建出新的url
module.exports = function combineURLs(baseURL, relativeURL) {
  return relativeURL
    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
    : baseURL;
    //如果传递了相对url,先将baseUrl结尾的斜杠后的所有字符删除,然后连接一个斜杠,然后再连接删除了开头斜杠的相对url
    //如果没有相对url参数,就直接返回baseUrl
};

 

posted @ 2018-11-22 11:29  hahazexia  阅读(483)  评论(0)    收藏  举报