axios
是在实际项目中应用比较多的请求插件了,提供给咱们的前置请求配置、响应拦截配置
,让咱们在实际应用中可以很好的利用;
node
不知道你们有没有这种时候,当身边的其余人都在看源码实现时候,本身却无从下手,看着超级多的逻辑,逐渐失去了兴趣,所以我发现我本身的看源码切入点,“好奇”
,看着项目配置中的“响应拦截”、“请求拦截”等,由心而生想要去知道这样究竟是如何实现的呢? 带着这种“好奇”我打开了axios的源码。ios
在看源码以前,必要的内容是先过一遍axios的使用方法,这样带着问题,会记忆深入ajax
axios
的配置大概分为三种axios
即在插件内部的默认配置api
在进行项目搭建时候,一般使用的自定义的全局配置数组
有的时候 在一个应用中须要实例化不一样的kxios
对象,针对不一样的接口 有利于管理,每一个实例化对象度灰有本身的配置,能够经过全局配置进行初始化,或合并成一个新的配置项目,实例配置通常是咱们进行本身配置的。promise
const nAxios = axios.create({
// baseURL: process.env.BASE_API,
// timeout: 5000,
withCredentials: true,
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
复制代码
在进行请求时候,对单个请求进行的配置浏览器
同一个实例会有一些公用的配置项目,如baseUrl,可是不少时候,不一样的请求具体的配置是不同的,如url、method
等,因此在请求的时候须要传入的配置与实例配置进行合并; 请求配置合并通常是这样子的?get请求的url ,后面的config都是咱们传入的请求配置,传入到项目中后,会merge
默认的配置,而后在进行请求;缓存
kxios.get('http://localhost:4000/',{
baseURL:'http://localhost:4000/',
methods:'get',
headers:{
'Content-Type':'333',
'Type':333
}
}).then((res)=>{
console.log("请求后的then")
console.log(res)
})
复制代码
请求配置
>实例配置
> 全局配置
markdown
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
复制代码
该文件提供了axios的实例构造器,即工厂函数
function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
// instance 绑定axios的默认数据 instance
var instance = bind(Axios.prototype.request, context);
// 复制axios的原型到实例中。此处主要是确保后续进行改变时候,不改变Axios的对象函数
utils.extend(instance, Axios.prototype, context);
//将实例绑定到Axios构造出得对象中
utils.extend(instance, context);
//instance 进行复制
return instance;
}
复制代码
Axios
的实例instance
绑定axios的默认数据instance
axios
的原型到实例中。此处主要是确保后续进行改变时候,不改变Axios
的对象函数Axios
构造出得对象中之因此选择这样,建立实例,而后在复制原型方法,是为了扩展axios自己更多的调用功能,在Axios
的函数中,具备复杂数据类型,保证每一个axios的实例在继承后都有独立的数据结构;
axios.get(url)
axios(url)
复制代码
在外界引用了axios
的方法就能进行建立axios的实例,并获得初始的默认值 进行调用
var nAxios = axios.create({
baseURL: process.env.BASE_API,
timeout: 5000,
withCredentials: true,
headers: {'X-Requested-With': 'XMLHttpRequest'}
})
//调用函数
nAxios.get('http:locallhost:888')
复制代码
对于nAxios.get('http:locallhost:888')
的执行的过程
Axios
的原型都附加上了请求方法,请求调用的时候直接调用时候,先进行merge
请求的配置,在进行调用config
的方法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
}));
};
});
复制代码
请求时候进行请求的调度,即去适配请求
在浏览器环境中主要是经过ajax进行请求
在浏览器中进行发送请求主要仍是以来XMLHttpRequest
咱们在实际的使用中,发现node环境和浏览器环境均可以使用axios,实际上是axios内部进行了适配;
//获取默认的请求适配器
function getDefaultAdapter() {
var adapter;
//若是当前存在XMLHttpRequest 这个对象,则进行XHr的额适配器
if (typeof XMLHttpRequest !== 'undefined') {
// 浏览器环境下使用XML这个适配器
adapter = require('./adapters/xhr')
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// node 环境下使用http这个模块适配器
adapter = require('./adapters/http');
}
return adapter;
}
复制代码
请求拦截器和响应拦截器帮助咱们在实际工做中去处理本身前置转换需求
/axios/lib/core/InterceptorManager.js
在该文件中定义了拦截器的构造函数InterceptorManager
,用于响应拦截和请求拦截的使用
function InterceptorManager() {
this.handlers = [];
}
//增长一个响应
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
//移除某一个
InterceptorManager.prototype.eject = function eject(id) {
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
复制代码
应用在Axios的构造函数中
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(), //请求拦截器
response: new InterceptorManager() // 响应拦截器
};
}
复制代码
请求拦截器和响应拦截器主要实现原理为Promise的链式执行方法;
// 拦截器中间件
//dispatchRequest为默认的主要请求内容 dispatchRequest返回一个promise的请求对象
var chain = [dispatchRequest, undefined];
//让config配置promise中,用来层级传递配置
var promise = Promise.resolve(config);
//请求拦截器
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
//将请求拦截器插入到 chain数组的前面,插入的原理实际上是 自定义配置时候越在后配置的先执行
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// 响应拦截器 将响应拦截器push 到chain 的后面 这样会后执行
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
//chain的结构 =[请求拦截器1,请求拦截器2,主要请求,响应拦截器1,响应拦截器2]
//执行chain中的方法
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
复制代码
这样就造成了一个拦截器的Promise队列
promise的then中 dispatchRequest.js
转换函数
module.exports = function transformData(data, headers, fns) {
/*eslint no-param-reassign:0*/
utils.forEach(fns, function transform(fn) {
data = fn(data, headers);
});
//返回转换后的数据
return data;
};
复制代码
建立实例的时候+调用接口数据的时候
取消请求的逻辑均在axios/lib/cancel
中,取消请求在配置中主要使用CancelToken进行控制,在请求中,也存在专门为CancelToken设置的方法, 在xhr.js中
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
//中止当前的请求
request.abort();
//而且进行reject
reject(cancel);
// Clean up request
request = null;
});
}
复制代码
cancelToken
的方法 中主要的一个做用在于执行阻止请求,并进行取消函数,进行下一个then的调用
看完axios ,本身收获仍是蛮多的,更多的是流程设计