axios.js的实战经验
总结一下使用
Axios.js
的遇到的注意事项,如有不对欢迎指正。本文不是一篇分析源码的文章,如果需要看源码解析看这里axios实例应用及源码剖析 - xhr篇 (走心教程),写的非常不错。
axios.js的流程图
先放张图镇楼,后续的问题需要多看看这张图。
axios.js版本问题
之前没有注意官网说明,后来升级了版本发现报错,立刻把官网的文档翻了一下,发现
Semver
章节有描述,直到v1.0之前,当发布一个minor版本,就代表有breaking changes了。所以升级有危险啊!!!
拦截器interceptor
拦截器是
axios.js
的核心了,就是有了拦截器做解耦,才能把代码组合的更优雅。
interceptor的返回值类型
当初在写拦截器时发现,官方给的例子,interceptor的返回值既可以是普通的value值,又可以是Promise。当时就疑惑了,有啥区别???
1 | // 官方例子: |
1 | // 源码里面就有一行代码 |
是不是瞬间就明白了拦截器的return值,其实可以是普通的value值,或者Promise对象。
返回Promise就有很多想法了,我们可以在拦截器
interceptor
中做异步操作,终于可以为所欲为了 :)。
interceptor的执行顺序
这个问题呢,是我在使用过程中纠结的一个问题,我想做一个功能,就是当
Content-Type: application/x-www-form-urlencoded;charset=utf-8
时候,自动把data
使用qs.stringify
(后来知道这个功能其实使用transformer
更合适)。
1 | // axios/lib/core/Axios.js |
上述代码其实就是做了两件事情:
把拦截器放入数组chain中
this.interceptors.request
拦截器是从chain
的头部放入;this.interceptors.request
其实也是数组,所以request
数组中最后放入的interceptor却在chain数组的最前面,和axios.interceptors.request.use
时候的顺序相反。this.interceptors.response
拦截器是放入chain
的尾部,所以interceptor顺序和添加axios.interceptors.response.use
时候的顺序相同
循环执行
chain
中的拦截器request
拦截器,最后添加的,最先执行response
拦截器,按照添加的顺序执行
注意:如果你的interceptors 之间顺序有先后依赖关系,需要特别注意。
transformer的使用
transformRequest
和transformResponse
都属于Axios.js
的transformer,官方宣传的Automatic transforms for JSON data
就是通过transformResponse
实现的。官方文档写的太简单了,没用写要注意的问题。
内置的transformRequest和transformResponse
默认处理JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 // axios/lib/defaults.js
var defaults = {
adapter: getDefaultAdapter(),
transformRequest: [function transformRequest(data, headers) {
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();
}
if (utils.isObject(data)) {
setContentTypeIfUnset(headers, 'application/json;charset=utf-8');
return JSON.stringify(data);
}
return data;
}],
transformResponse: [function transformResponse(data) {
/*eslint no-param-reassign:0*/
if (typeof data === 'string') {
try {
data = JSON.parse(data);
} catch (e) { /* Ignore */ }
}
return data;
}],
};
1 | // transformRequest |
- 如果data是
URLSearchParams
类型,axios把Content-Type
修改为application/x-www-form-urlencoded;charset=utf-8
,且序列化data - 如果data是Object,axios把
Content-Type
修改为application/json;charset=utf-8
,且序列化data transformResponse
默认尝试解析JSON
内置transformRequest和transformResponse被覆盖
内置的
transformRequest
和transformResponse
,很容易被覆盖,如果你不需要内置的那就很好办,如果你需要就需要注意下。
1 | import axios from 'axios'; |
自动序列化data参数且修改Content-Type
注意
URLSearchParams
兼容性问题,如果兼容IE 11,使用qs
处理下。
- 如果data是URLSearchParams类型,axios把
Content-Type
修改为application/x-www-form-urlencoded;charset=utf-8
,且序列化data- 如果data是Object,axios把
Content-Type
修改为application/json;charset=utf-8
,且序列化data
transformer和interceptor的区别
transformer和interceptor都能在请求过程中发挥作用,有啥区别呢?
区别:
- transformer和interceptor的执行的时机不同,看上图
- transformer主要针对data(虽然也能直接改变header,但是不建议)
- transformer只能同步,而interceptor可以执行异步操作
1 | module.exports = function transformData(data, headers, fns) { |
baseUrl配置
axios内部判断config.url,如果是绝对路径开始就不添加baseUrl,否则就添加
1 | // axios/lib/core/dispatchRequest.js |
二进制数据注意
如果你的
transformer
和interceptor
对data
有变形或者使用,一定要先判断二进制,不然容易导致报错。
推荐的做法就是,使用单独的axios
实例处理二进制数据。
多个axios
实例之间,注意共享headers
部分(这个坑,我已经踩进去了)。
总结
以上是本人使用
axios.js
过程中遇到的疑惑,然后通过查看源码的总结,如果对你有帮助,我会感到很荣幸。