记录-使用proxy拦截axios.get()接口请求

284 阅读4分钟

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)
    })

这样我们在控制台可以看到打印的结果,由此可类似于我们项目中接口请求的调用

image.png

那么如果要实现某些接口的拦截的话,我们就要能够监控到它什么时候调用该方法,并且拿到该方法调用时所拿到的参数

了解学习proxy的作用后,我了解到了proxy的拦截操作一共有13中,而本次所可能需要的只有其中两种

image.png image.png

其实最开始的时候我一直使用的是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进行操作就可以了。

image.png

大致实现代码如下:

//当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实现其实是同理

控制台输出如下:

image.png

--基本实现原理就是这样,因为源代码分布比较散,所以就不粘贴了