发送请求
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 };