axios手动封装之拦截器

762 阅读6分钟
拦截器是在使用 axios 中用的比较多的,所以今天我们来看看 axios 的拦截器是怎么做的,在分析源码的同时,我会自己借鉴 axios 源码来实现 axios 拦截的功能,这样既能够学到源码的思维,在面试过程中,也可以吹吹牛

首先,如果如果对 Promise 和普通 Ajax 的封装如果不是很熟悉的话,可以看看我之前写的:

《axios手动封装之准备工作》

其次,我之前手动封装了 axios 的 GET/POST/PUT/DELETE 的基于 XMLHttprequests 请求:

《axios手动封装GET/POST/PUT/DELETE》

首先我们来展示一下 axios 拦截器的使用

axios 拦截器的使用

同样的我们需要使用 json-serve 来模拟后端接口(《axios手动封装之准备工作》里面对 json-serve 有详细的介绍)

创建一个文件夹 server,在此文件夹中新建一个文件 db.json


执行命令

json-server --watch --port 53000 db.json

这个时候会开启服务


如果显示这样的界面,说明已经开启成功,那么本地访问 http://localhost:53000/data 就可以访问到数据

这个时候新建 html 文件,并使用 axios cdn 进行引用


呈现出来的界面是这样的


当我们点击 get 请求的时候,得到的结果是:


结果不用解释,但是有一个奇怪的现象,就是 请求拦截2 先触发,再是 请求拦截1,而 响应拦截1 先触发 ,再是 响应拦截2,是不是一个奇怪的现象,带着这个疑问,我们接续来看

axios 源码中的拦截思想的实现

在 axios 源码中关于怎么实现拦截功能的,将拦截方法和请求放在同一个 chain 数组里面


在 chain 的数组里面循环遍历里面的方法,并且使用 Promise 去依次调用,就可以实现在请求之前和请求之后对请求的进行拦截

源码部分

在 axios 的源码工程中,core/Axios.js 中 在 Axios 的原型上绑定了 request 方法


分析

  1、创建一个 chain 数组,数组初始化有两个元素,是 dispatchRequest ,undefined,dispatchRequest 就是真实请求的方法,为什么要加 undefined 呢,是因为,在我们在添加请求拦截和响应拦截的时候,是两个方法两个方法放进这个数组的,而且使用 Promise 执行的时候也是两个方法两个方法执行,如果初始值只有一个,在使用 Promise 执行的时候,就会出现问题。

  2、创建一个方法 promise 直接执行 Promise.resolve

// 定义方法
 var promise = Promise.resolve(config);

  3、遍历 request ,将 Promise 的成功和失败的回调函数 unshift 到数组 chain 里面,放到 chain 的最前面,就是把执行请求拦截,放到请求之前。

  4、遍历 response,将 Promise 的成功和失败的回调函数 push 到数组 chain 里面,放到 chain 的最后面,就是把执行响应拦截,放到请求之后


  5、然后通过执行 while 循环,使用 Promise 依次去两两去执行 chain 数组里面的方法,使用数组方法 shift 会删除数组前面的数据,并且返回删除项,这样依次去执行了 chain 数组里面的方法,并且依次删除 chain 里面的数据


那么我们这个时候来解释一下,刚开始的时候,为什么会出现,如果我们有两个请求和响应拦截的时候,为什么会先触发 请求拦截2 的方法,因为 unshift 将后面的请求的拦截放到了最前面,而响应拦截的时候我们使用的是 push 方法,那么它才会依次去执行 响应拦截1 响应拦截2

自己来实现 axios 的拦截

那么前面已经分析和解释了axio 源码中的主要思想,这里结合 axios 源码,和在前面写的文章 《axios手动封装之准备工作》和 《axios手动封装GET/POST/PUT/DELETE》 的基础上进行改进,跟 axios 的源码思想是一致的

Axios 函数


Axios 构造函数里面有 interceptors 对象,对象里面的两个属性 requset 和 response

InterceptorManager 函数


我们需要一个专门来管理拦截器的函数

use 函数


当使用 use 的时候将两个回调存放到 this.handlers 数组里面 

dispatchRequest 函数


这个方法就是上篇文章我们写的封装 get/post/put/delete的方法

request 函数


这个函数就是我们前面分析的处理拦截器的核心思想

测试用例

测试的 html 结构 

引入我们自己封装的 axios 本地文件


拦截测试代码

由于是自己封装的需要 new Axios


同样的我们使用了两个请求拦截和响应拦截

打印 axios 对象

打印一下 axios 对象在使用了拦截之后的数据


我们可以看到,在使用拦截之后,分别在 request 和 response 的 handlers 数组里面存有我们的

测试函数


查看结果


我们可以看到结果跟使用 原本的 axios 的结果是一样的

那么我们再来测试一下,真的在拦截里面执行添加属性能不能实现

升级测试


为了查看结果,在 dispatchRequest 函数中打印 config


点击发送 get 请求


这就是本次封装的结果,还有很多情况没有考虑到,比如只能使用request去发请求等等,但是这篇的核心是拦截器的封装,其他就不做过多的处理。由于代码量比较大,如果需要我的源代码可以去我的 github 上去下载,源码,在 github 下载的时候麻烦给 star

另外,写博客不容易,如果觉得对你有帮助,麻烦给一个赞,谢谢了


最后:本人喜欢研究面试题,希望有更多志同道合的朋友一起来交流研究,可以帮助修改简历