原文地址javascript
总结一下使用
Axios.js
的遇到的注意事项,若有不对欢迎指正。java本文不是一篇分析源码的文章,若是须要看源码解析看这里axios实例应用及源码剖析 - xhr篇 (走心教程),写的很是不错。ios
先放张图镇楼,后续的问题须要多看看这张图。git
以前没有注意官网说明,后来升级了版本发现报错,马上把官网的文档翻了一下,发现
Semver
章节有描述,github直到v1.0以前,当发布一个minor版本,就表明有breaking changes了。因此升级有危险啊!!!typescript
拦截器是
axios.js
的核心了,就是有了拦截器作解耦,才能把代码组合的更优雅。json
当初在写拦截器时发现,官方给的例子,interceptor的返回值既能够是普通的value值,又能够是Promise。当时就疑惑了,有啥区别???axios
// 官方例子:
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
复制代码
// 源码里面就有一行代码
promise = promise.then(chain.shift(), chain.shift());
// 其实把上面例子翻译一下就是这样的
// Add a request interceptor
promise = promise.then(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
promise = promise.then(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
复制代码
是否是瞬间就明白了拦截器的return值,其实能够是普通的value值,或者Promise对象。promise
返回Promise就有不少想法了,咱们能够在拦截器
interceptor
中作异步操做,终于能够随心所欲了 :)。
这个问题呢,是我在使用过程当中纠结的一个问题,我想作一个功能,就是当
Content-Type: application/x-www-form-urlencoded;charset=utf-8
时候,自动把data
使用qs.stringify
(后来知道这个功能其实使用transformer
更合适)。
// axios/lib/core/Axios.js
// 核心逻辑就是这段
var chain = [dispatchRequest, undefined]; // 正中间的是发送请求的拦截器
var promise = Promise.resolve(config);
// request 拦截器unshift,添加到数组的头部
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
// response 拦截器 push到数组尾部
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
// 循环执行拦截器
promise = promise.then(chain.shift(), chain.shift());
}
复制代码
上述代码其实就是作了两件事情:
把拦截器放入数组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 之间顺序有***前后依赖关系***,须要特别注意。
transformRequest
和transformResponse
都属于Axios.js
的transformer,官方宣传的Automatic transforms for JSON data 就是经过transformResponse
实现的。官方文档写的太简单了,没用写要注意的问题。
默认处理JSON
// 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;
}],
};
复制代码
// transformRequest
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);
}
复制代码
URLSearchParams
类型,axios把Content-Type
修改成application/x-www-form-urlencoded;charset=utf-8
,且序列化dataContent-Type
修改成application/json;charset=utf-8
,且序列化datatransformResponse
默认尝试解析JSON内置的
transformRequest
和transformResponse
,很容易被覆盖,若是你不须要内置的那就很好办,若是你须要就须要注意下。
import axios from 'axios';
const defaults = { // 须要把默认的添加回来
transformRequest: [].concat(axios.defaults.transformRequest, (data, headers) => {
// do something
return data;
})
};
复制代码
Content-Type
注意
URLSearchParams
兼容性问题,若是兼容IE 11,使用qs
处理下。
Content-Type
修改成application/x-www-form-urlencoded;charset=utf-8
,且序列化dataContent-Type
修改成application/json;charset=utf-8
,且序列化datatransformer和interceptor都能在请求过程当中发挥做用,有啥区别呢?
区别:
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内部判断config.url,若是是绝对路径开始就不添加baseUrl,不然就添加
// axios/lib/core/dispatchRequest.js
// Support baseURL config
if (config.baseURL && !isAbsoluteURL(config.url)) {
config.url = combineURLs(config.baseURL, config.url);
}
复制代码
若是你的
transformer
和interceptor
对data
有变形或者使用,必定要先判断二进制,否则容易致使报错。 推荐的作法就是,使用单独的axios
实例处理二进制数据。 多个axios
实例之间,注意共享headers
部分(这个坑,我已经踩进去了)。
以上是本人使用
axios.js
过程当中遇到的疑惑,而后经过查看源码的总结,若是对你有帮助,我会感到很荣幸。
关注公众号,发现更多精彩内容。
![]()