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。