axios怎么实现拦截器?为什么要实现拦截器?
拦截器的作用
我们现在说说这个问题。
axios的拦截器作用非常大。axios的拦截器分为请求拦截器跟响应拦截器,都是可以设置多个请求或者响应拦截。每个拦截器都可以设置两个拦截函数,一个为成功拦截,一个为失败拦截。在调用axios.request()之后,请求的配置会先进入请求拦截器中,正常可以一直执行成功拦截函数,如果有异常会进入失败拦截函数,并不会发起请求;调起请求响应返回后,会根据响应信息进入响应成功拦截函数或者响应失败拦截函数。
因此,我们可以在拦截器中处理一些请求的统一处理。比如在请求拦截器中设置请求头,处理统一的请求数据,在响应拦截去中根据响应状态码做统一的提示信息,整理响应数据等。
// 官方用例
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
如果有一些请求有特有的拦截需求,还可以添加后再删除:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
拦截器的源码实现
关于拦截器的源码实现,其实在第一篇的源码分析中已经涉及到主要的部分了。
我们可以观察一下拦截器的写法,跟Promise.then的写法是很像的。说明内部的实现也会跟手写promise的实现差不多。事实上源码的实现多少也有点那个味。
axios中的拦截器是一个类,然后会在创建Axios实例时创建两个拦截器实例,一个作为请求拦截,一个作为相应拦截。
// 拦截器源码
function InterceptorManager() {
// 通过axios.interceptors.use来设置拦截器,然后推入handlers中,然后就可以设置多个拦截器
this.handlers = [];
}
// Axios源码
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = { // 拦截器
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
然后当用户调axios.interceptors.[request/response].use()(其实这个名字挺长的,作者也没有在Axios下设置别名,估计觉得这样写语义更强吧)时,就是调拦截器的use方法。这个方法会把传入的两个函数进行组合入栈this.handlers,然后返回对应的下标。
// InterceptorManager源码
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1; // 返回当前拦截器的index,作为拦截器的id
};
当用户调用axios.interceptors.request.eject()时,会拿传入的id去把栈this.handlers中对应下标的内容置空。
// InterceptorManager源码
InterceptorManager.prototype.eject = function eject(id) {
// id是在use注册拦截器的时候返回
// 这里根据拦截器的id来删除
if (this.handlers[id]) {
this.handlers[id] = null;
}
};
当用户调用axios.request()时,内部会调用请求跟响应拦截器的InterceptorManager.prototype.forEach拿到每一组拦截函数,然后推入数组chain中。
// Axios源码
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);
});
实际到之后,在调用拦截函数时,已经不是在拦截器实例中调用了,所以拦截器的作用更多是一个存储栈的作用,实现的3个api也是在做栈的处理。所以不如说InterceptorManager是拦截器存储栈类(类名直译也是拦截器管理的意思)。
以上就是axios拦截器的实现分析。下一篇会整理一下axios整个处理流程。