@jsongao98
2021-04-24T12:17:46.000000Z
字数 3388
阅读 95
工具
jq纯回调方式封装ajax(XHR),所以需要先把callback写好再请求
axios基于promise来封装XHR,链式
从浏览器创建XHR,node.js创建http请求
返回promise对象,支持Promise API,并发请求promise.all
拦截请求和响应,支持取消请求
转换请求数据和响应数据,自动转换JSON数据
客户端支持防御XSRF
axios返回一个promise对象,response.status如果是200-300,则该promise对象的state为resolved,执行then。如果是400,404等,则执行catch。有时候我们需要对不同的状态码进行不同操作,(细分状态码,axios promise只分成功失败),所以一般对axios再进行封装。
axios({
method:'get',
url:'http://bit.ly/2mTM3nY',
responseType:'stream',
data:...,//post请求是data为请求正文
params:...,//get请求不需要请求正文(request payload)
})
.then(function(response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
axios(url[,config])默认get方法
也可以这么写:
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
在axios请求配置中使用new操作符调用,传入一个函数参数(包含取消请求的函数),函数将取消请求的函数保存到一个外部变量中。
axios.isCancel()是否是一个取消请求的错误
axios.create([config])
1). 根据指定配置创建一个新的axios,也就是每个axios都有自己的配置(如果没有自己的配置,你还创建他干啥)
2). 新axios只是没有取消请求和批量发请求的方法,其他语法都是一样的
3). 为什么要设计这么个语法?
假设你的项目很大,后端有多个host,使用一个axios显然不能很好的解决这个问题.
所以,你需要针对每一个axios对象设置一个baseURL和其他配置属性,也就是使用create语法创建多个不同配置的axios拦截器函数/ajax请求/请求回调函数的调用顺序(源码)
1). 调用axios()并不是马上发送ajax请求,需要经历一系列流程
2). 假如你添加了两个请求拦截器和响应拦截器
流程: 请求拦截器2 => 请求拦截器1 => ajax请求 => 响应拦截器1 => 响应拦截器2
为啥请求拦截器先添加后执行,而响应拦截器却先添加先执行?这个问题后面看到源码便一目了然,莫方~
3). 此流程是通过promise串联的,请求拦截器传递的是配置config,响应拦截器传递的是response
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;
};
源码分析:
这个request方法就是axios发送请求的核心方法,在源码中将发送请求分为了几个部分(请求拦截器,发送请求,响应拦截器,响应回调),通过Promise的链式调用将这些部分有机地结合了起来,这样就构成了发送请求拿到数据处理的全部过程。
- 1.代码开始构建了一个config配置对象,用于第一次执行Promise返回一个成功的promise
- 2.最核心的数组chain,这个数据中保存了请求拦截器函数,响应拦截器函数和默认就有的发送请求的函数,第一步返回的成功的promise对象,将遍历这个数组逐一执行里面的函数,并返回新的Promise对象
- 3.往数组中添加请求拦截器函数,依照axios请求的执行顺序,请求拦截器应该在发送请求之前执行,故应该添加在发送请求函数的前面,所以使用的是数组的unshift方法,这个方法意思是头部添加,即后面添加的元素总是在头部
- 4.往数组中添加请求拦截器函数,依照axios请求的执行顺序,响应拦截器应该在发送请求之后执行,故应该添加在发送请求函数的后面,所以使用的是数组的push方法,这个方法意思是尾部添加,即后面添加的元素总是在尾部
- 5.promise遍历执行,使用的while循序,使用数组的shift方法每次从中取出两个函数执行(成功回调,失败回调)
- 6.返回Promise对象,用于执行我们指定的响应数据的回调
取消请求的流程
1). 配置cancelToken对象
2). 缓存用于取消请求的cancel函数
3). 在特定的时机下调用cancel函数
4). 在error回调中判断,如果error是cancel,做相应处理
总流程图