持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第31天,点击查看活动详情
axios是基于Promise的HTTP请求库,封装了XHR简化了我们对xhr的使用,其中axios中的拦截器可以说是其一大亮点了。
使用
//引入
import axios from "axios";
// 设置请求拦截器 config 配置对象
axios.interceptors.request.use(function one(config) {
console.log('请求拦截器成功 1');
return config;
}, function (error) {
console.log('请求拦截器失败 1');
return Promise.reject(error);
});
axios.interceptors.request.use(function two(config) {
console.log('请求拦截器成功 2');
return config;
}, function (error) {
console.log('请求拦截器失败 2');
return Promise.reject(error);
});
// 设置响应拦截器
axios.interceptors.response.use(function (response) {
console.log('响应拦截器成功 1');
return response;
}, function (error) {
console.log('响应拦截器失败 1');
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
console.log('响应拦截器成功 2');
return response;
}, function (error) {
console.log('响应拦截器失败 2');
return Promise.reject(error);
});
// 发送请求
axios({
method: 'GET',
url: 'http://localhost:3000/posts'
}).then(response => {
console.log(response);
});
上面的代码就是对拦截器的基本使用,拦截器分为请求前拦截,请求拦截器可以在发出请求之前,按照拦截器添加顺序执行,再发送请求。而响应拦截器则是在收到响应之后,按照拦截器添加顺序执行后,再返回响应结果。主要作用如下:
- 数据转换
- 添加额外的数据,例如往header添加信息等
- 日志记录,输出请求响应时间和失败率等
实现
我们简单的实现一下整个过程,由于只是实现拦截器所以XHR的东西我们就直接省略不写了。
首先是我们的构造函数,接受我们传入的参数,同时有一个实例属性interceptions里面有两个属性,分别是我们的请求前拦截和响应后拦截,各是一个拦截器管理器实例对象
function Axios (config) {
this.axios = config;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager(),
}
}
拦截器管理器构造函数有个属性是处理对象集,
// 拦截器管理器构造函数
function InterceptorManager () {
this.handlers = [];
}
同时拥有一个use实例方法来将拦截后的成功处理和失败处理方式压入处理对象集中。
InterceptorManager.prototype.use = function (fulfilled, rejected) {
this.handlers.push({
fulfilled,
rejected
})
}
首先遍历请求拦截器按照顺序将处理函数添加到数组前部,然后遍历响应拦截器按照顺序将处理函数添加到数组末尾
// 发送请求
Axios.prototype.request = function (config) {
// 创建一个 promise 对象
let promise = Promise.resolve(config);
// 创建一个数组
const chains = [dispatchRequest, undefined];
// 处理拦截器
// 请求拦截器 将请求拦截器的回调 压入到 chains 的前面 request.handles = []
this.interceptors.request.handlers.forEach(item => {
chains.unshift(item.fulfilled, item.rejected);
});
// 响应拦截器
//响应拦截器,将响应拦截器的回调压入chains的后面 request.handles=[]
this.interceptors.response.handlers.forEach(item => {
chains.push(item.fulfilled, item.rejected);
});
// 遍历
while (chains.length > 0) {
promise = promise.then(chains.shift(), chains.shift());
}
return promise;
}
// 发送请求
function dispatchRequest (config) {
// 返回一个 promise 队列
return new Promise((resolve, reject) => {
resolve({
status: 200,
statusText: 'OK'
});
});
}
测试
// 创建实例
let context = new Axios({});
// 创建 axios 函数
let axios = Axios.prototype.request.bind(context);
//将 context 属性 config interceptors 添加至 axios 函数对象身上
Object.keys(context).forEach(key => {
axios[key] = context[key];
});
// 设置请求拦截器 config 配置对象
axios.interceptors.request.use(function one(config) {
console.log('请求拦截器成功 1');
return config;
}, function (error) {
console.log('请求拦截器失败 1');
return Promise.reject(error);
});
axios.interceptors.request.use(function two(config) {
console.log('请求拦截器成功 2');
return config;
}, function (error) {
console.log('请求拦截器失败 2');
return Promise.reject(error);
});
// 设置响应拦截器
axios.interceptors.response.use(function (response) {
console.log('响应拦截器成功 1');
return response;
}, function (error) {
console.log('响应拦截器失败 1');
return Promise.reject(error);
});
axios.interceptors.response.use(function (response) {
console.log('响应拦截器成功 2');
return response;
}, function (error) {
console.log('响应拦截器失败 2');
return Promise.reject(error);
});
// 发送请求
axios({
method: 'GET',
url: 'http://localhost:3000/posts'
}).then(response => {
console.log(response);
});