axios源码解析-拦截器

本文详细介绍了Axios拦截器的工作原理,包括InterceptorManager的构造函数和use方法,以及如何将拦截器加入执行链。拦截器的成功和失败回调被保存在数组中,通过下标进行管理,便于添加、删除和执行。在请求和响应过程中,拦截器的执行链确保了同步和异步操作的正确顺序。拦截器的使用和删除机制简化了对请求和响应的处理,同时在链式调用中起到了关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

axios源码解析-拦截器

之前我们介绍了Axios这个对象,其中,Axios的拦截器部分很简单,只是给请求和响应各创建了一个InterceptorManager的实例,那么,今天我们就来看看InterceptorManager究竟干了什么事情

function InterceptorManager() {
    // 处理方法作为数组依次执行
    this.handlers = [];
}

我们可以看到,InterceptorManager这个构造函数的结构页很简单,只是定义了一个用来处理的数组而已,有了前面Axios的基础,我们可能很容易想到,拦截器是不是用数组去保存一组函数呢?那么,接下来他调用use方法的部分就有趣了

InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
    this.handlers.push({
        // 成功会调
        fulfilled: fulfilled,
        // 失败回调
        rejected: rejected,
        // 是否为同步函数
        synchronous: options ? options.synchronous : false,
        runWhen: options ? options.runWhen : null
    });
    return this.handlers.length - 1;
    // 注意这里返回的是一个下标,函数利用下标值来完成对拦截器的删除或调用
};

我们发现,use这个方法 本质上只是只是将拦截器的成功/失败回调,配置保存到一个数组里,并不进行任何处理。其实,拦截器的处理是跟dispatchRequest一起的,都被放入执行链进行执行
我们再仔细看Axios.js中的代码

 // filter out skipped interceptors
    // 拦截器链
    var requestInterceptorChain = [];
    // 是否为同步函数
    var synchronousRequestInterceptors = true;
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
            return;
        }
        // 确保每个请求拦截器都是同步的,最终的拦截器才是同步的
        synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
        // 将每个请求拦截器的成功回调和失败回调绑定在执行链的最前端
        requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    var responseInterceptorChain = [];
    // 注意这里的foreach方法是拦截器原型链上的foreach方法
    // 这个方法内部会遍历所有拦截器
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        // 将每个响应拦截器加入到执行链的最后端
        responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });

可以看出,最后被加入执行链的,也仅仅是拦截器中的两个回调函数,而 synchronous这个配置用于判断函数是否是同步函数,拦截器函数的执行,是被放在执行链调用的部分进行的
另一个有意思的点,是use这个方法返回的居然是数组的下标,在此之前,我一直意味返回的应该是一个函数或对象之类的,那么,为什么他要返回一个下标呢,其实这是为了简化删除拦截器的方法而准备的

//通过use方法拿到id,利用id删除对应元素
InterceptorManager.prototype.eject = function eject(id) {
    if (this.handlers[id]) {
        this.handlers[id] = null;
    }
};

我们可以看到,我们删除一个拦截器,本质上就是将拦截器数组对应下标的元素置空,那么也就是说,只要我们知道了这个拦截器的索引,就可以通过索引找到并删除这个拦截器了。因此,我们在创建拦截器时,只要用一个变量保存这个拦截器在数组中的下标,删除时就可以通过相同的变量对其进行删除
另外注意一点,就是官网上拦截器实例的返回值

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });

我们可以看到,请求和响应拦截器的成功回调都是链式对请求响应数据进行修改,因此每次调用都返回了更新后的配置,让下一级继续调用,链式调用的传参也是在这里进行的。而失败的请求,则是返回一个Promise的失败回调,并将参数传入。这里要注意一下
在InterceptorsManger的原型链上,还挂载了一个对拦截器进行统一操作的方法foreach

InterceptorManager.prototype.forEach = function forEach(fn) {
    utils.forEach(this.handlers, function forEachHandler(h) {
        if (h !== null) {
            // 对于数组的每一项,只要有值就调用该函数(确认还没有被销毁)
            // 这里的fn就是将所有拦截器放入执行链的push
            fn(h);
        }
    });
};

这里外层的foreach主要是将函数作为参数进行传递,而内部utils上的foreach,则是遍历这个数组的每一项,并将每一项作为参数让外部传进来的函数进行调用。这个方法在Axios.js中的应用是将所有的拦截器方法放入执行链中,我们同样可以调用它对拦截器上的所有方法做一些统一处理

//在Axios.js中的调用示例
    this.interceptors.response.forEach(function 
    	pushResponseInterceptors(interceptor) {
        // 将每个响应拦截器加入到执行链的最后端
        	responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });

拦截器的实现,主要是用统一模型,控制拦截器的注册,销毁,执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值