写了几年项目,也用了几年的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.methodconfig.method = (config.method || this.defaults.method || 'get').toLowerCase();// config的method优先从传进来的取,如果使用者没有传递,则使用默认config里面的method,默认的没有则默认getconst 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 interceptorsconst 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就是一个请求接口的一个封装插件,,提供很多方法让你去使用