axios拦截器 config_axios拦截器的实现
拦截器设计与实现
#需求分析
我们希望能对请求的发送和响应做拦截,也就是在发送请求之前和接收到响应之后做一些额外逻辑。
我们希望设计的拦截器的使用方式如下:
// 添加一个请求拦截器
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);
});
在 axios 对象上有一个 interceptors 对象属性,该属性又有 request 和 response 2 个属性,它们都有一个 use 方法,use 方法支持 2 个参数,第一个参数类似 Promise 的 resolve 函数,第二个参数类似 Promise 的 reject 函数。我们可以在 resolve 函数和 reject 函数中执行同步代码或者是异步代码逻辑。
并且我们是可以添加多个拦截器的,拦截器的执行顺序是链式依次执行的方式。对于 request 拦截器,后添加的拦截器会在请求前的过程中先执行;对于 response 拦截器,先添加的拦截器会在响应后先执行。
axios.interceptors.request.use(config => {
config.headers.test += '1'
return config
})
axios.interceptors.request.use(config => {
config.headers.test += '2'
return config
})
此外,我们也可以支持删除某个拦截器,如下:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/})
axios.interceptors.request.eject(myInterceptor)
#整体设计
我们先用一张图来展示一下拦截器工作流程:
整个过程是一个链式调用的方式,并且每个拦截器都可以支持同步和异步处理,我们自然而然地就联想到使用 Promise 链的方式来实现整个调用过程。
在这个 Promise 链的执行过程中,请求拦截器 resolve 函数处理的是 config 对象,而相应拦截器 resolve 函数处理的是 response 对象。
在了解了拦截器工作流程后,我们先要创建一个拦截器管理类,允许我们去添加 删除和遍历拦截器。
#拦截器管理类实现
根据需求,axios 拥有一个 interceptors 对象属性,该属性又有 request 和 response 2 个属性,它们对外提供一个 use 方法来添加拦截器,我们可以把这俩属性看做是一个拦截器管理对象。use 方法支持 2 个参数,第一个是 resolve 函数,第二个是 reject 函数,对于 resolve 函数的参数,请求拦截器是 AxiosRequestConfig 类型的,而响应拦截器是 AxiosResponse 类型的;而对于 reject 函数的参数类型则是 any 类型的。
根据上述分析,我们先来定义一下拦截器管理对象对外的接口。
#接口定义
types/index.ts:
export interface AxiosInterceptorManager {
use(resolved: ResolvedFn, rejected?: RejectedFn): number
eject(id: number): void
}
export interface ResolvedFn {
(val: T): T | Promise
}
export interface RejectedFn {
(error: any): any
}
这里我们定义了 AxiosInterceptorManager 泛型接口,因为对于 resolve 函数的参数,请求拦截器和响应拦截器是不同的。
#代码实现
import { ResolvedFn, RejectedFn } from '../types'
interface Interceptor {
resolved: ResolvedFn
rejected?: RejectedFn
}
export default class InterceptorManager {
private interceptors: Array | null>
constructor() {
this.interceptors = []
}
use(resolved: ResolvedFn, rejected?: RejectedFn): number {
this.interceptors.push({
resolved,
rejected
})
return this.interceptors.length - 1
}
forEach(fn: (interceptor: Interceptor) => void): void {
this.interceptors.forEach(interceptor => {
if (interceptor !== null) {
fn(interceptor)
}
})
}
eject(id: number): void {
if (this.interceptors[id]) {
this.interceptors[id] = null
}
}
}
我们定义了一个 InterceptorManager 泛型类,内部维护了一个私有属性 interceptors,它是一个数组,用来存储拦截器。该类还对外提供了 3 个方法,其中 use 接口就是添加拦截器到 interceptors中,并返回一个 id 用于删除;forEach 接口就是遍历 interceptors 用的,它支持传入一个函数,遍历过程中会调用该函数,并把每一个 interceptor 作为该函数的参数传入;eject 就是删除一个拦截器,通过传入拦截器的 id 删除。
#链式调用实现
本小节需要你对 Promise 掌握和理解,可以前往 mdn 学习。
当我们实现好拦截器管理类,接下来就是在 Axios 中定义一个 interceptors 属性,它的类型如下:
interface Interceptors {
request: InterceptorManager
response: InterceptorManager
}
export default class Axios {
interceptors: Interceptors
constructor() {
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
}
}
}
Interceptors 类型拥有 2 个属性,一个请求拦截器管理类实例,一个是响应拦截器管理类实例。我们在实例化 Axios 类的时候,在它的构造器去初始化这个 interceptors 实例属性。
接下来,我们修改 request 方法的逻辑,添加拦截器链式调用的逻辑:
core/Axios.ts:
interface PromiseChain {
resolved: ResolvedFn | ((config: AxiosRequestConfig) => AxiosPromise)
rejected?: RejectedFn
}
request(url: any, config?: any): AxiosPromise {
if (typeof url === 'string') {
if (!config) {
config = {}
}
config.url = url
} else {
config = url
}
const chain: PromiseChain[] = [{
resolved: dispatchRequest,
rejected: undefined
}]
this.interceptors.request.forEach(interceptor => {
chain.unshift(interceptor)
})
this.interceptors.response.forEach(interceptor => {
chain.push(interceptor)
})
let promise = Promise.resolve(config)
while (chain.length) {
const { resolved, rejected } = chain.shift()!
promise = promise.then(resolved, rejected)
}
return promise
}
首先,构造一个 PromiseChain 类型的数组 chain,并把 dispatchRequest 函数赋值给 resolved 属性;接着先遍历请求拦截器插入到 chain 的前面;然后再遍历响应拦截器插入到 chain 后面。
接下来定义一个已经 resolve 的 promise,循环这个 chain,拿到每个拦截器对象,把它们的 resolved 函数和 rejected 函数添加到 promise.then 的参数中,这样就相当于通过 Promise 的链式调用方式,实现了拦截器一层层的链式调用的效果。
注意我们拦截器的执行顺序,对于请求拦截器,先执行后添加的,再执行先添加的;而对于响应拦截器,先执行先添加的,后执行后添加的。
#demo 编写
在 examples 目录下创建 interceptor 目录,在 interceptor 目录下创建 index.html:
Interceptor example
接着创建 app.ts 作为入口文件:
import axios from '../../src/index'
axios.interceptors.request.use(config => {
config.headers.test += '1'
return config
})
axios.interceptors.request.use(config => {
config.headers.test += '2'
return config
})
axios.interceptors.request.use(config => {
config.headers.test += '3'
return config
})
axios.interceptors.response.use(res => {
res.data += '1'
return res
})
let interceptor = axios.interceptors.response.use(res => {
res.data += '2'
return res
})
axios.interceptors.response.use(res => {
res.data += '3'
return res
})
axios.interceptors.response.eject(interceptor)
axios({
url: '/interceptor/get',
method: 'get',
headers: {
test: ''
}
}).then((res) => {
console.log(res.data)
})
该 demo 我们添加了 3 个请求拦截器,添加了 3 个响应拦截器并删除了第二个。运行该 demo 我们通过浏览器访问,我们发送的请求添加了一个 test 的请求 header,它的值是 321;我们的响应数据返回的是 hello,经过响应拦截器的处理,最终我们输出的数据是 hello13。
至此,我们给 ts-axios 实现了拦截器功能,它是一个非常实用的功能,在实际工作中我们可以利用它做一些需求如登录权限认证。
我们目前通过 axios 发送请求,往往会传入一堆配置,但是我们也希望 ts-axios 本身也会有一些默认配置,我们把用户传入的自定义配置和默认配置做一层合并。其实,大部分的 JS 库都是类似的玩法。下面一章我们就来实现这个 feature。
axios拦截器 config_axios拦截器的实现相关推荐
- axios拦截器 config_axios拦截器
页面发送http请求,很多情况我们要对请求和其响应进行特定的处理:如果请求数非常多,单独对每一个请求进行处理会变得非常麻烦,程序的优雅性也会大打折扣.好在强大的axios为开发者提供了这样一个API: ...
- axios 最全 请求拦截器 响应拦截器 配置公共请求头 超时时间 以及get delete post put 四种请求传参方式
axios 拦截器 请求拦截器 请求拦截器的作用是在请求发送前进行一些操作 例如在每个请求体里加上token,统一做了处理如果以后要改也非常容易 响应拦截器 响应拦截器的作用是在接收到响应后进行一些操 ...
- axios 请求拦截器响应拦截器
一. 拦截器介绍 一般在使用axios时,会用到拦截器的功能,一般分为两种:请求拦截器.响应拦截器. 请求拦截器 在请求发送前进行必要操作处理,例如添加统一cookie.请求体加验证.设置请求头等,相 ...
- vue 无法进入response拦截器_vue拦截器的一次实践
起因 最近在做一个项目前端框架使用的是vue,项目接近尾声的时候发现需要增加一个对所有的http请求过滤的功能,所有的请求需要加上token再发送给服务器,服务器根据token判断用户身份是否有效,响 ...
- jfinal js 拦截_jfinal 使用拦截器处理繁琐的前置条件判定
使用拦截器处理繁琐的前置条件判定 背景 在开发过程中,为了提高程序的健壮性,对参数的校验是必不可少的,然而使用传统的方式进行参数校验时,导致程序中存在了if xxx return xxx;处理不够优雅 ...
- springboot拦截器拦截提示_Springboot拦截器使用及其底层源码剖析
博主最近看了一下公司刚刚开发的微服务,准备入手从基本的过滤器以及拦截器开始剖析,以及在帮同学们分析一下上次的jetty过滤器源码与本次Springboot中tomcat中过滤器的区别.正题开始,拦截器 ...
- springmvc拦截器无法拦截jsp
为什么80%的码农都做不了架构师?>>> 问题:spring mvc的拦截器只拦截controller不拦截jsp文件,如果不拦截jsp文件也会给系统带安全性问题. 解决方案: ...
- Struts2 自定义拦截器(方法拦截器)
转自:http://05061107cm.iteye.com/blog/365504 struts2系统自带了很多拦截器,有时需要我们自己定义,一般有两种方式: 一.实现Interceptor接口 J ...
- Struts2 拦截器: 拦截器与过滤器区别
1.首先要明确什么是拦截器.什么是过滤器 1.1 什么是拦截器: 拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加 ...
最新文章
- es对分组后结果进行统计_ElasticSearch里面如何分组后根据sum值排序
- 人工智能的炒作_解密人工智能:是炒作还是我们期望太高
- php验证时区是否存在,php – 验证来自不同网站的时区名称?
- 正则基础学习1 这俩天补上正则全部内容,让你简单的学会正则,欢迎收藏当文档
- python中beautifulsoup_面向新手解析python Beautiful Soup基本用法
- PWN-PRACTICE-BUUCTF-10
- 程序员谈网络改变我们的生活
- android 生命周期流程图,Android Studio ——Service的生命周期
- 贝叶斯数据分析_科研进阶项目 | 剑桥大学 | 心理学、社会学、生物医学:统计数据分析(6.13开课)...
- 电脑黑屏的原因有哪些
- android 线程池 阻塞队列,【Android框架进阶〖02〗】ThinkAndroid线程池机制
- CPU+GPU异构集群搭建的总结说明
- TP6使用redis
- 猴子摘香蕉问题python_用Basic STRIPS算法求解猴子和香蕉
- background背景图片铺满背景并且不重复
- 转载了别人的cocos2d-x的学习笔记
- pca图解读_PCA 图像识别 详解(一)
- 解决第三方平台超时问题
- 数学物理方法·基础④复平面/辐角/复数表示形式
- CentOS7下安装Hadoop伪分布式
热门文章
- Linux系统下使用docker来部署Redis集群
- csh/tcsh脚本札记(持续更新:2021-8-24)
- pcap判断是否oracle,pcap的使用之pcap_findalldevs
- 证件照制作v2.9.38
- Beta冲刺(7/7)——2019.5.28
- Ubuntu/centos网络接口没有eth0但是有eth1或eth2的问题
- c#(服务器)与java(客户端)通过socket传递对象_C#(服務器)與Java(客戶端)通過Socket傳遞對象...
- 数据分析---常见分类算法
- 【Web技术】981- 手摸手之前端覆盖率实践
- 我的高效编程的秘诀:自动化你的编程工作