创建两个类
编写请求拦截和响应拦截的时候就调用use将请求拦截的方法和响应拦截的方法分别存入两个对应的实例中。
实例中的实例属性handlers数组就是用来保存对应的方法的。
class InterceptorManager{
constructor() {
this.handlers=[];
this.name="hansu"
}
use(resolve,reject){
this.handlers.push({resolve,reject})
}
forEach(fn){
this.handlers.forEach((elem)=>{
fn(elem)
})
}
}
class Http{
constructor() {
this.config={};
this.interceptors={
request:new InterceptorManager(),
response:new InterceptorManager(),
}
}
initConfig(config){
Object.assign(this.config,config)
}
}
export default new Http()创建执行链
执行的顺序大概是:请求前配置一些数据->发起请求->对请求数据做一些调整。很明显这是一条链状的结构,用链式调用再好不过,于是就使用promise进行链式调用。
实现原理也很简单,将一开始创造的两个实例中的handlers分别添加到执行链中的头部和尾部,将要发起请求的promise放在中间。
dispatchRequest是当前即将要发送的一个请求,先存入chains中
调用InterceptorManager实例中的forEach方法,向chain的头部和尾部分别插入请求拦截的回调函数和响应拦截的回调函数,因为创建的实例对象不同,所以有所区分
最后循环调用chains即可
具体实现:
class Request {
get(url, data = {}) {
let config={
url,
data,
method,
header:{}
};
function getPromise(config){
return new Promise((resolve, reject) => {
uni.request({
...config,
success: (res) => {
resolve(Object.assign({config},res))
//将config和res组成新的对象返回,这样可以拿到配置信息
}
})
})
}
function dispatchRequest(config){
if(http.config.baseURL){
config.url=http.config.baseURL + url
}
//添加baseURL
return getPromise(config)
}
let chain=[dispatchRequest,undefined];
//创建执行链
http.interceptors.request.forEach(function(interceptor){
chain.unshift(interceptor.resolve,interceptor.reject)
//一个是接受状态的回调,一个是拒绝状态的回调
})
//在执行链头部中添加请求拦截时传入的方法
http.interceptors.response.forEach(function(interceptor){
chain.push(interceptor.resolve,interceptor.reject)
})
//在执行链尾部中添加响应拦截时传入的方法
let promise=Promise.resolve(config);
//初始化状态就是 resolved,这里形成了promise调用链,就可以直接promise.then()了
while(chain.length){
promise=promise.then(chain.shift(),chain.shift())
//返回chain中第一个元素的值,并将其删除,因为都是成对出现的resolve和reject回调
}
return promise
}
post(url, data = {}){
return this.get(url,data,"POST")
}
}
export default Request请求拦截和响应拦截
import http from "@/config/http"
http.initConfig({
baseURL:"http://192.168.1.14:10009/",
timeout:10000
})
//请求拦截
http.interceptors.request.use((config)=>{
// console.log("ready to request")
config.header['x-Token']="sdada";
return Promise.resolve(config)
})
//响应拦截
http.interceptors.response.use((res)=>{
console.log(res.config.method)
if (res.statusCode == 200) {
let data=JSON.parse(res.data);
if((data.length>0||Object.keys(data).length>0)&&data){
}
else{
uni.showToast({
title:"暂无数据",
icon:"none"
})
}
return Promise.resolve(data)
} else {
return Promise.reject("HTTP:状态码异常!");
}
})注意点:
1.请求拦截无非就是在请求之前增加一些配置,那如何修改请求中的配置呢?我可以预先初始化一个config,然后通过初始化一个Promise.resolve(config)进行传递。然后在请求拦截的函数中做修改。
2.请求完成后返回的结果会通过resolve传递到响应拦截的方法中,最后做完操作后,通过return将值返回出来。
3.then通常都会有两个回调函数,一个是接受状态,一个是拒绝的状态,所以如果没有传入拒绝的状态就设置为undefined,这样比较规范,以防万一有的传一个,有的传两个,在调用promise的时候不会出错。
4.返回的结果需要和最初的config进行合并,在响应拦截中可以读取最开始的config
5.config的变化
最开始的值是调用get或者post等方法传入的值
然后发送请求的时候会结合Http类中的config的实例属性,做一些修改
最后请求完毕会将config和res合并一起返回
具体可以参考以下文档