一文解析axios源码
写了几年项目,也用了几年的axios,但是一直也不是很了解其中的原理,为啥他能请求前拦截,也为啥他能响应后拦截,正好有空,所以对他的源码进行分析,从github把他的源码拉下来进行分析:
从package.json可以看出主入口:index.js
查看/lib/axios.js
lib/axios.js 主要一个createInstance 创建一个实例的方法,我们使用axios的时候,都是这样使用的,如下面的代码所示,axios.create就是上面的方法创建的
// 创建axios实例
const service = axios.create({
baseURL: '',
timeout: 20000, // 请求超时时间
headers: {
'Content-Type': 'multipart/form-data'
}
})
在继续看看new Axios里面干了啥,找到lib/core/Axios.js文件,分解来看,剔除了一些非核心代码,核心代码如下:
class Axios {
constructor(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
async request(configOrUrl, config) {
try {
return await this._request(configOrUrl, config);
} catch (err)
}
}
_request(configOrUrl, config) {
const requestInterceptorChain = [];
let synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor)
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
const responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
let promise;
let i = 0;
let len;
if (!synchronousRequestInterceptors) {
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift.apply(chain, requestInterceptorChain);
chain.push.apply(chain, responseInterceptorChain);
len = chain.length;
promise = Promise.resolve(config);
while (i < len) {
promise = promise.then(chain[i++], chain[i++]);
}
return promise;
}
len = requestInterceptorChain.length;
let newConfig = config;
i = 0;
while (i < len) {
const onFulfilled = requestInterceptorChain[i++];
const onRejected = requestInterceptorChain[i++];
try {
newConfig = onFulfilled(newConfig);
} catch (error) {
onRejected.call(this, error);
break;
}
}
try {
promise = dispatchRequest.call(this, newConfig);
} catch (error) {
return Promise.reject(error);
}
i = 0;
len = responseInterceptorChain.length;
while (i < len) {
promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
}
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(mergeConfig(config || {}, {
method,
url,
data: (config || {}).data
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
function generateHTTPMethod(isForm) {
return function httpMethod(url, data, config) {
return this.request(mergeConfig(config || {}, {
method,
headers: isForm ? {
'Content-Type': 'multipart/form-data'
} : {},
url,
data
}));
};
}
Axios.prototype[method] = generateHTTPMethod();
Axios.prototype[method + 'Form'] = generateHTTPMethod(true);
});
核心步骤解析:
1、创建Axios类,构造函数中定义请求拦截和响应拦截
查看lib/core/InterceptorManager.js 文件new InterceptorManager(),主要是一个handlers数组,即
class Axios {
constructor(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: [],
response:[]
};
}
}
2、查看上述核心代码最后两段utils.forEach([‘delete’, ‘get’, ‘head’, ‘options’],即把这些都放到Axios.prototype[method]的原型上,当我们在使用axios.get的时候就是调用这里,而这里的方法其实就是调用this.request,而调用this.request则是调用_request方法
3、_request方法分析
_request(configOrUrl, config) {
config = mergeConfig(this.defaults, config); // 默认config与传jinlaid的config进行合并
// Set config.method
config.method = (config.method || this.defaults.method || 'get').toLowerCase();// config的method优先从传进来的取,如果使用者没有传递,则使用默认config里面的method,默认的没有则默认get
const requestInterceptorChain = [];
let synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
const responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
let promise;
let i = 0;
let len;
if (!synchronousRequestInterceptors) {
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift.apply(chain, requestInterceptorChain);
chain.push.apply(chain, responseInterceptorChain);
len = chain.length;
promise = Promise.resolve(config);
while (i < len) {
promise = promise.then(chain[i++], chain[i++]);
}
return promise;
}
len = requestInterceptorChain.length;
let newConfig = config;
i = 0;
while (i < len) {
const onFulfilled = requestInterceptorChain[i++];
const onRejected = requestInterceptorChain[i++];
try {
newConfig = onFulfilled(newConfig);
} catch (error) {
onRejected.call(this, error);
break;
}
}
try {
promise = dispatchRequest.call(this, newConfig);
} catch (error) {
return Promise.reject(error);
}
i = 0;
len = responseInterceptorChain.length;
while (i < len) {
promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);
}
return promise;
}
你可能有点懵,我们先来看看axios的请求拦截器和响应拦截器是怎么使用的,我们是不是都跟下面的代码一样使用的拦截器?
// 请求拦截器
service.interceptors.request.use(
config =>
},
error => {
}
)
// 响应拦截器
service.interceptors.response.use(
response =>
},
error => {
}
)
查看InterceptorManager.js代码,这里的use方法就是往handlers里面push
再看_request核心代码:先把this.interceptors.request请求拦截器数组里面全都用unshift放入到requestInterceptorChain数组里面,把this.interceptors.response响应拦截器数组里面的全部用push放入到responseInterceptorChain,然
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift.apply(chain, requestInterceptorChain);
chain.push.apply(chain, responseInterceptorChain);
请求拦截器+当前请求+响应拦截器的这是不是连接起来了? 这就是为什么在你发一个请求的时候,因为他是一条链,先zhi行请求拦截器,等所有的拦截器执行完,在执行当前请求,等你当前请求执行完再执行响应拦截器,全连起来了!
// filter out skipped interceptors
const requestInterceptorChain = [];
let synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
return;
}
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
const responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
const chain = [dispatchRequest.bind(this), undefined];
chain.unshift.apply(chain, requestInterceptorChain);
chain.push.apply(chain, responseInterceptorChain);
len = chain.length;
promise = Promise.resolve(config);
while (i < len) {
promise = promise.then(chain[i++], chain[i++]);
}
return promise;
dispatchRequest则是调用请求的一个方法,其实就是XMLHttpRequest那一套,做了一个适配器的封装,暂不叙述!
所以综合起来看axios就是一个请求接口的一个封装插件,,提供很多方法让你去使用