axios package - dynamic loading, data caching

cutting edge

After reading a lot of axios packages on the Internet, I feel that they are not particularly perfect. So I plan to write a relatively complete package including the following functions (not all completed yet, continuously updated):

  1. Header settings when uploading and downloading files
  2. Error corresponding unified handling
  3. Dynamically load the api (done)
  4. Data cache (completed), clear cache (completed), cache level (completed), maximum number of caches (completed)
  5. Intercept repeated requests (completed), cancel the request when the page jumps
  6. refresh token

That's all I can think of for now, if you have any other ideas, please leave a message to me

1. Dynamic loading

 It is troublesome to import the corresponding file every time you request it.

// 引入
import { add } from "@/api/tool/code";
// 在方法中
add()

The advantage of this is that there is no need to load a large number of APIs at the beginning. The disadvantage is that each page needs to be imported manually, especially for some common interfaces, which need to be introduced in many interfaces.

Using the Proxy object can realize the automatic loading of the api, of course, the Proxy can also use some public methods to automatically load when accessing the object method.

let api = {};
api = new Proxy(api, {
    // apiName是访问api下的对象名称也作为文件名称和文件里所有api的名字,在数据缓存中有相关处理
    get(target, apiName) {
        if (target[key] === undefined) { //在访问api的属性是判断是否有这个属性没有的话就按照名字和固定的路径去加载文件,然后挂载上去,最后返回。
            console.log(target, apiName);
            //加载路径可以根据自己的api放置位置和规则修改
            let obj = require('./api/' + apiName + '.js').default;
            target[apiName] = {};
            for (let item in obj) {
                target[key][item] = (data) => {
                    return request(obj[item](data), apiName);
                }
            }
        }
        return target[key];
    }
})

export default api;  //这里导出,最后挂载到全局

2. Data caching and interception of repeated requests

const service = axios.create({
    // 设置请求超时时间
    baseURL: '/api',
    timeout: 20000,
    headers: {
        'content-type': 'application/json', // 设置请求体类型
        /*
        常用的请求格式有:
            'application/json': 发送JSON对象
            'multipart/form-data': 需要文件上传时,就使用该格式
        
        根据后台需求发送其他需要放在header里面数据,例如:
            'Authorization': 'Basic ****', //登录验证
        */
    },
    // 默认情况下,后台状态码不返回200的话,是不会收到返回数据的,可以根据需要设置后台返回状态码的区间
    validateStatus: function(status) {
        return status >= 200 && status <= 500;
    },
    // 请求时是否携带cookie信息
    withCredentials: true,
})

// 定义最大缓存数量
const MAXCACHE = 5;
// 定义缓存对象
let caChe = {
    list: [],
    // 每个请求都有缓存级别,数字越小缓存级别越高
    add(data) {
        // 找到相同或小于当前级别的缓存的下标
        let index = this.list.findIndex(item => {
            return item.level ? data.level < item.level : true;
        })
        // 如果没有找到就插入到最前面,如果有就插入到这个缓存的前面
        if (index <= 0) {
            this.list.unshift(data);
        } else {
            this.list.splice(index, 0, data);
        }
        // 如果达到最大缓存数量,删除最后一个
        if (this.list.length > MAXCACHE) {
            this.list.pop();
        }
    },
    // 找到这个key的缓存
    find(key) {
        return this.list.find(item => {
            return key === item.key;
        })
    },
    // 根据api名称删除缓存
    deleteApiName(apiName) {
        this.list = this.list.filter(item => {
            return item.apiName !== apiName;
        })
    }
};
// 定义一个正在请求的列表,用来防止重复请求
let request_list = {};

let request = (params, apiName) => {
    // 使用哈希MD5函数将 url、params、data 的数据组成一个key,这里使用HmacMd5就是不想这个key太长
    let key = params.url + HmacMd5(JSON.stringify(params.params) + JSON.stringify(params.data)).toString();
    console.log(key);
    //如果request_list[key]有值则是判断为重复请求
    if (request_list[key]) {
        console.log('接口正在请求,等待返回');

        return Promise.reject({
            code: 301,
            msg: '请求中,请稍等',
        });
    // 判断缓存中是否有,有的话直接返回
    } else if (caChe.find(key) !== undefined) {
        console.log('有缓存,直接返回数据');
        return Promise.resolve(caChe.find(key).response_data);
    } else {
        return new Promise((resolve, reject) => {
            console.log('没有缓存,发起请求');
            
            // 添加key标识接口正在请求
            request_list[key] = { apiName };
            
            service(params).then(res => {

                resolve(res.data);
                
                // 如果不是get请求就删除对应apiName的缓存,例如:
                // 请求用户列表后缓存了返回数据,当我添加或修改了某一个用户后,在获取就应该请求数据而不是拿缓存中的数据;我这里的apiName为文件名
                if (params.method !== 'get') {
                    caChe.deleteApiName(apiName);
                } else if (params.isCache || params.isCache === undefined) {
                    // 判断接口是否需要缓存,接口默认为缓存
                    caChe.add({
                        response_data: res.data,
                        key,
                        apiName,
                        level: params.level,
                    })
                }
            }).catch(err => {
                reject(err.data);
            }).finally(() => {
                // 不管成功与否都删除正在请求列表中对应的key,方便下次请求
                delete request_list[key];
            })
        })
    }
}

3. API package file



let user = {
    get: ({ current, size }) => {
        return {
            url: '/user',
            method: 'get',
            isCache: true, // 是否缓存,不写默认为缓存
            level: 0, // 缓存级别
            params: { current, size }
        }
    },
    post: (data) => {
        return {
            url: '/user',
            method: 'post',
            data: {
                name: data.name,
                age: data.age
            }
        }
    },
    put: ({ id, name, age }) => {
        return {
            url: '/user',
            method: 'put',
            data: { id, name, age },
        }
    },
    delete: ({ id }) => {
        return {
            url: '/user',
            method: 'delete',
            params: { id: id },
        }
    }
}

export default user;

Guess you like

Origin blog.csdn.net/qq_18676843/article/details/122983122