axios(六)-- 请求 / 响应拦截器是如何生效的?

Axios 中的公共方法

1、关键点

假设1个请求拦截和1个相应拦截
一开始栈的数据就两个(dispatchRequest是 ajax请求)
[dispatchRequest ,undefined] --> undefined 是为了后面一对一对的
如果拦截器存在,就要往栈中加数据 (unshift)
[rejected1, fulfilled1, dispatchRequest, undefined]
请求结束后,如果还有拦截,就要继续添加,(添加在请求完后面 push)
[rejected1, fulfilled1, dispatchRequest, undefined, fulfilled1, rejected1]
每次出栈就一对的出栈,因为 promise 一个成功一个失败,

2、使用

// 拦截器
const myInterceptor = axios.interceptors.request.use(function (config) {
    // 在发送之前做点什么
    console.log(request1)
    return config
}, function(error) {
    // 在请求错误做些什么
    return error
})
 axios.interceptors.request.use(function (config) {
    // 在发送之前做点什么
    console.log(request2)
    return config
}, function(error) {
    // 在请求错误做些什么
    return error
})

 axios.interceptors.response.use(function (config) {
    // 在发送之前做点什么
     console.log(request1)
    return config
}, function(error) {
    // 在请求错误做些什么
    return error
})
 axios.interceptors.response.use(function (config) {
    // 在发送之前做点什么
     console.log(request2)
    return config
}, function(error) {
    // 在请求错误做些什么
    return error
})

// 移除拦截器
axios.interceptors.request.eject(myInterceptor)

// 执行顺序 request2 -> request1 -> response1 -> response2

3、源码(综合了前面的源码)

import InterceptorManager from './InterceptorManager.js'
import dispatchRequest from './dispatchRequest.js'

// 1、配置:外部传入,可覆盖内部默认配置
// 2、拦截器:实例后,开发者可通过 `use` 方法注册成功和失败的钩子函数,
// 比如 `axios.interceptors.request.use((config)=>config,(error)=>error);`
function Axios(instanceConfig) {
  // 配置
  this.defaults = instanceConfig;
  // 拦截器实例
  // 每个 Axios 实例上都有 interceptors 属性,该属性上有 request、response 属性,
  // 分别都是一个 InterceptorManager 实例,而 InterceptorManager 构造函数就是
  // 用来管理拦截器
  this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
  };
}
生成请求与响应拦截队列,形成promise链(综合了上一篇的)
Axios.prototype.request = function request(config) {
    // 为了支持 request(url, {...}), request({url, ...})
    // 方式二:axios('https://xxxx') ,判断参数字符串,则赋值给 config.url
    if (typeof config === 'string') {
      config = arguments[1] || {};
      config.url = arguments[0];
    } else {
      // 方式一:axios({}) ,参数为对象,则直接赋值给 config
      config = config || {};
    }

    // 配置优先级: 调用方法的配置 > 实例化axios的配置 > 默认配置
    // 举个例子,类似:axios.get(url, {}) > axios.create(url, {}) > 内部默认设置
    config = mergeConfig(this.defaults, config);
    // 生成请求拦截队列
    var requestInterceptorChain = [];
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
        requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });

    // 生成响应拦截队列
    var responseInterceptorChain = [];
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
        responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });

    /*
    创建用于保存请求/响应拦截函数的数组
    数组的中间放发送请求的函数
    数组的左边放请求拦截器函数(成功/失败)
    数组的右边放响应拦截器函数
    undefined为啥? -->  因为拦截器是成对存在的,所以此处用undefined占位,后续在promise链中可以同前面的一对一对拿出移除
    */

    // 编排整个请求的任务队列
    // 派发请求 dispatchRequest 看下篇
    var chain = [dispatchRequest, undefined];  

    // 为什么unshift要用Array.prototype.unshift.apply??
    Array.prototype.unshift.apply(chain, requestInterceptorChain);

    chain.concat(responseInterceptorChain);

    var promise;
    // 传入配置
    promise = Promise.resolve(config);
    // 形成 promise 链条调用
    // 循环 chain ,不断从 chain 中取出设置的任务,通过 Promise 调用链执行 , 一对一对拿出,一个成功一个失败处理
    while (chain.length) {
      promise = promise.then(chain.shift(), chain.shift());
    }
    // ...
    return promise;
  };

// Provide aliases for supported request methods   utils.forEach(数组, 函数)-> 循环数组并执行函数
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});
// 与平时用的forEach的区别:对象也可以传,并遍历出对象的键值
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

定义拦截器:

handlers []: 存放 use 注册的回调函数
use function: 注册成功和失败的回调函数
eject function: 删除注册过的函数

// 拦截器
export class InterceptorManager {
    constructor() {
        // 存放所有拦截器的栈
        this.handlers = []
    }
    use (fulfilled, rejected) {
        this.handlers.push({
            fulfilled,
            rejected
        })
        // 返回id,便于取消
        return this.handlers.length - 1
    }
    // 取消一个拦截器
    eject (id) {
        if (this.handlers[id]) {
            this.handlers[id] = null
        }
    }
    // 执行栈中所有的handler
    forEach(fn) {
        this.handlers.forEach(item => {
            // 此处过滤掉已取消的
            if (item) {
                fn(item)
            }
        })
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值