proxy俗称'代理器',可以用来拦截一个目标对象中的一些操作,相当于在这个目标对象的前方设置了一个拦截,当我们要访问目标对象时需要经过这个拦截。
在本次需求开发中,开发要求某些接口请求一次后要进行数据缓存,这样下次请求直接拿缓存数据就可以了;
按正常的逻辑来说,我们一般使用vuex来缓存接口数据,这样在下一个地方请求前判断store中是否有数据缓存,如果有缓存直接拿store里边的数据就可以避免接口多次请求了;
- 但是如何在不改变原有的代码的情况下实现接口数据缓存呢?
因为项目页面太多,之前页面中并不知道哪个页面使用了这个接口,如果一一修改就太浪费时间了,所以只能在接口上的拦截找方法了。
最开始一直觉得要使用请求拦截器(axios.interceptors.request.use),但是如果使用接口拦截器,就代表我们的请求已经发出去了,我们在f12检查网络时也可以看到重复发请求,所以必须要在请求前就能够设置拦截,并且能够把数据返回给接口。
后来技术leader说可以思考一下proxy的作用,我就使用了proxy进行尝试。
1. 先自己定义了一个类似axios对象,设置get和post方法
let axios = {
name: 'studyproxy',
get(url) {
let p = new Promise(function (resolve, reject) {
if (url) {
resolve('get');
} else {
reject('getaaaa');
}
})
return p
},
post(url) {
let p = new Promise(function (resolve, reject) {
if (url) {
resolve('111');
} else {
reject('222');
}
})
return p
}
}
2. 接口请求的写法
axios.get('aaa').then(res => {
console.log('get----', res)
})
这样我们在控制台可以看到打印的结果,由此可类似于我们项目中接口请求的调用
那么如果要实现某些接口的拦截的话,我们就要能够监控到它什么时候调用该方法,并且拿到该方法调用时所拿到的参数
了解学习proxy的作用后,我了解到了proxy的拦截操作一共有13中,而本次所可能需要的只有其中两种
其实最开始的时候我一直使用的是get进行的拦截,但是get只能拦截到读取,却没有办法获取参数;后来研究发现proxy是可以监听实例作为函数调用的操作的,并且所传的args就是对象调用所传的参数
3.拦截axios.get(参数)请求
let proxy = new Proxy(axios.get, {
apply(target, ctx, args) { //对象作为函数调用时拦截
console.log('apply拦截---target', target);
console.log('apply拦截---ctx',ctx);
console.log('apply拦截---args',args);
return Reflect.apply(...arguments)
}
})
axios.get = proxy; //对axios.get()进行重新的封装
axios.get('aaa',{name:1}).then(res => {
console.log('get----', res)
})
此时我们查看控制台,我们不仅可以监听到axios.get()的使用,还能拿到请求时携带的参数,并且还不会改变原有的数据请求编码,而我们所需要的操作只需要在proxy里边的apply进行操作就可以了。
大致实现代码如下:
//当get请求接口时 aaa 时 返回 apply
let axios = {
name: 'studyproxy',
get(url) {
let p = new Promise(function (resolve, reject) {
if (url) {
resolve('get');
} else {
reject('getaaaa');
}
})
return p
},
post(url) {
let p = new Promise(function (resolve, reject) {
if (url) {
resolve('111');
} else {
reject('222');
}
})
return p
}
}
let store={
data:'apply'
}
//可以看作是vue中的axios
let proxy = new Proxy(axios.get, {
apply(target, ctx, args) { //对象作为函数调用时拦截
console.log('apply拦截---target', target);
console.log('apply拦截---ctx',ctx);
console.log('apply拦截---args',args);
let url=args[0];//拿到请求的url
let data=store.list;//拿到缓存数据
if(url=='aaa'){ // 如果匹配符合,则看是否有缓存数据(在项目中需要在响应拦截器中设置第一次请求时的缓存) if(data){
return Promise.resolve(data);
}
}
return Reflect.apply(...arguments);
}
})//可以在axios封装时进行axios.get的封装
axios.get = proxy; //重新赋值给axios
axios.get('aaa',{name:1}).then(res => {
console.log('get----', res)
}) //页面中请求的编码
//因为项目需要只有get接口中的数据进行了缓存,所以post实现其实是同理
控制台输出如下:
--基本实现原理就是这样,因为源代码分布比较散,所以就不粘贴了