-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
7、请求相关 #8
Comments
Axios使用及源码分析背景
Axios介绍Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中
Axios基本使用一般使用请求如下,符合Restful风格 axios.request(config)
axios.get(url, config)
axios.delete(url, config)
axios.head(url, config)
axios.post(url, data, config)
axios.put(url, data, config)
axios.patch(url, data, config)
config配置参数可自定义:
config = {
baseURL: 'http://esp-homework-api', //请求域名
headers: XXX, //请求头,可添加自定义参数
ignoreErrorCodes: ['XXX','XXX'], // 全局统一拦截时,如果配置该参数,则不会走错误拦截处理
methods: 'POST', //没设置methods时,默认是GET请求
timeout: 500
}
function getUser1() {
return axios.get('/user/818118');
}
function getUser2() {
return axios.get('/user/910604');
}
axios.all([getUser1(), getUser2()])
.then(axios.spread(function (data1, data2) {
// 两个请求都完成时,处理逻辑,data1、data2分别代表两个请求返回的结果
}));
Axios实际上是一个Promise,所以上述请求等同于下面的写法:
Promise.all([getUser1(), getUser2()]).then(([data1, data2])=> {
两个请求都完成时,处理逻辑
})
{
data:{}, //真实返回数据,前端需要处理的
status:200,
statusText:'OK',
headers: {},
config: {}
}
可以测试下请求返回数据
axios.get('/user/818118')
.then(function(res){
console.log(res.data);
console.log(res.status);
console.log(res.statusText);
console.log(res.headers);
console.log(res.config);
})
网络请求发出去之前进行拦截:
axios.interceptors.request.use(function(config){
return config;
},function(err){
return Promise.reject(error);
});
实际使用场景,可以设置auth参数:
axios.interceptors.request.use(function(config=> {
config.headers['Authorization'] = 'xxx'
})
网络请求返回之前进行拦截:
axios.interceptors.response.use(function(res){
return res;
},function(err){
return Promise.reject(error);
});
实际使用场景,因为axios实际返回是一个结构体,包含data数据,所以我们可以直接拦截返回给前台调用:
axios.interceptors.response.use(function(response=> {
return response.data
}) 源码分析主要分析拦截器的相关源码,在这之前,我们有必要回顾下Promise的知识 getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL);
}).then(function funcA(comments) {
console.log("resolved: ", comments);
}, function funcB(err){
console.log("rejected: ", err);
});
第一个then方法指定的回调函数,返回的是另一个Promise对象。这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。如果变为resolved,就调用funcA,如果状态变为rejected,就调用funcB 整个拦截的过程,大概如下: interceptors.request -> request -> interceptors.response -> response 我们现在来看下Axios类的定义 function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
结合上面的使用方式axios.interceptors.request.use,interceptors主要是由一个InterceptorManager类的实例实现。
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
InterceptorManager的功能简单地讲,只是通过一个数组来维护拦截器,每个拦截器的两个参数分别作为Promise中的resolve和reject InterceptorManager的使用是在Axios类中 Axios.prototype.request = function request(config) {
// 挂载interceptor中间件
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);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
当执行request请求时,会遍历之前定义的interceptors拦截器,通过一个数组chain维护,经过遍历逻辑后,chain变量变为:
[interceptor.request.fulfilled, interceptor.request.rejected,
dispatchRequest, undefined,
interceptor.response.fulfilled, interceptor.response.rejected]
while方法循环包装成一个promise返回:
Promise.resolve(config)
.then(interceptor.request.fulfilled, interceptor.request.rejected)
.then(dispatchRequest, undefined)
.then(interceptor.response.fulfilled, interceptor.response.rejected)
这样就是之前我们说的promise嵌套使用。
开发过程中,有使用过实例化axios的方法 var instance = axios.create({
baseURL:"https://some-domain.com/api/"}); 但是新实例化的对象不会执行之前定义的拦截器方法,我们分下下创建实例的源码 function createInstance(defaultConfig) {
var context = new Axios(defaultConfig);
var instance = bind(Axios.prototype.request, context);
utils.extend(instance, Axios.prototype, context);
utils.extend(instance, context);
return instance;
}
// Factory for creating new instances
axios.create = function create(instanceConfig) {
return createInstance(utils.merge(defaults, instanceConfig));
};
因为重新实例化后,不会将原先定义的参数同步过来,需要自己重新配置 总结Axios的有点在于既能在web,又能在node中使用,而且轻量级。我们在阅读源码时,可以学习它的封装思路,有助于在工程中实践。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
fetch
之前在项目中用到了这个fetch 来代替Ajax 进行网络请求。也踩了不少的坑,在这边列举出来以及他的解决方法。
如何保持每次请求的会话一致
在用fetch进行网络请求的时候,发现每次请求到服务端的时候,他的sessionId 都是不一样的,后面排查原来是在请求的时候fetch默认是不会带上本地jsessionId,以至于服务端无法接收到,所以会重新创建一个新的session。
兼容性,支持IE10+、谷歌、火狐等
由于fetch是一个新技术,有些旧的浏览器对它并不支持,这时候要怎么兼容?
解决办法:
引入一个额外的补丁es6-promise.js可以使它很好的支持IE9以上的版本,那IE8呢?IE8 需要改fetch.js源码才能支持
fetch.js 只需改两处:
try里面的是源码本身的,catch里面的是小编额外加的。细心的会发现这两处改的是一样的,都是对getOwnPropertyNames进行替换。但是IE8也不支持forEach为啥没有替换 呢? 其实有替换了,只是不再这边体现。我把它写进了Array.prototype里面了,其实fetch.js里面也用到了indexOf,它在IE8下也是不支持,我把它一并的放在Array.prototype;如下:
The text was updated successfully, but these errors were encountered: