接口数据缓存在浏览器

1,387 阅读4分钟

最近的工作中需要实现将部分接口的数据缓存在页面以减少请求、加快页面响应的需求,现总结一下实现这个需求的过程

具体需求

缓存数据的场景分为两种:

  1. 与用户无关的数据
  2. 与用户相关的数据

需要使用缓存的接口是无参数且为get类型的请求

应用内代码简介

这是一个使用vue-cli创建的vue2.0项目,使用axios库来发送接口请求

大致思路

  1. 对于用户无关的数据,可以存储在localStorage
  2. 对于用户相关的数据,可以存储在sessionStorage
  3. 不修改原有的接口使用方法,创建一个新的接口调用函数,并使调用方式保持不变
// 发送请求并将数据缓存到localStorage的方法
// 参数axiosConfig为普通axios方法所使用的参数
export function localRequest(axiosConfig) {
    // service为axios.create方法创建的实例
    return service(axiosConfig);
}
  1. 调用该方法时,先创建用于保存的key,再在对应的storage中查找是否有该key的缓存值,有则返回一个伪造的axios请求的Promise结果对象
export function localRequest(axiosConfig) {
    // 先创建缓存数据在localStorage中的key,由于请求皆为无参数的get请求,所以仅用url作为key即可
    // LOCALSTORAGE_CACHE_VERSION是一个存储版本号,后面有详细解释
    const localKey = axiosConfig.url + LOCALSTORAGE_CACHE_VERSION;
    // 尝试去获取localStorage中的缓存值,并封装为一个伪造的axios方法返回值
    const storeResponse = getStoreResponse(localKey, window['localStorage']);
    if(storeResponse) {
        // 如果本地有存储的值,则上面的方法会返回一个Promise实例
        return storeResponse;
    }
    // 本地没有缓存则调用接口去请求数据
    return service(axiosConfig);
}
// 获取存储中的数据
function getStoreResponse(localKey, storage) {
    const item = storage.getItem(localKey);
    if(item) {
        try {
            const data = JSON.parse(item);
            if(data) {
                // 成功拿到
                return Promise.resolve({
                    status: 200,
                    statusText: 'ok',
                    data,
                })
            }
        } catch (err) {
            // 这里不做任何处理
        }
    }
    // 如果未取到缓存中的结果,则会返回undefined
}
  1. 没有缓存时请求到数据后需要将响应数据保存在本地存储中,并且需注意的是要对请求结果做判断,只保存成功拿到数据的结果,否则一次失败后将无法再获取成功的结果
export function localRequest(axiosConfig) {
    // ...
    // 省略部分代码
    if(StoreResponse) {
        return storeResponse;
    }
    // 在axios方法参数中配置请求成功后的处理
    axiosConfig.transformResponse = [
        data => {
            const jsonData = JSON.parse(data);
            // 判断请求结果是否ok
            if(jsonData.code === 'sucess') {
                // 只保存成功响应的结果
                window['localStorage'].setItem(locakKey, data);
            }
            return jsonData;
        }
    ];
    return service(axiosConfig);
}

至此,该localRequest便可以用于替换axios.create创建的实例,来请求可以缓存于本地的用户无关数据

  1. 创建用于缓存数据到localStorage的key时,使用了LOCALSTORAGE_CACHE_VERSION常量,该常用是使用webpack.DefinePlugin插件注入的值,这样是为了让每次重新发版后可以自动刷新本地缓存的数据
// vue.config.js中
{
    configureWebpack: {
        // webpack配置
        plugins: [
            new webpack.DefinePlugin({ 
                // 这里使用Date.now()即可,为了美观也可以使用uuid或nanoid库
                // 必须要使用JSON.stringify()方法给普通值加一对引号,否则会报错
                LOCALSTORAGE_CACHE_VERSION: JSON.stringify(Date.now()) 
            })
       ]
    }
}
  1. 创建sessionRequest方法来请求用户相关的数据,与localRequest的区别在于key的创建
// 创建local缓存的key由参数路径和本地存储版本号组成
const localKey = axiosConfig.url + LOCALSTORAGE_CACHE_VERSION;
// 创建session缓存的key需由用户id+参数路径组成
const sessionKey = store.state.userInfo.userId + axiosConfig.url;
// 一般而言无需考虑session缓存的版本号,因为其随着页面关闭就会消失
  1. 关于session缓存用户相关的数据,如果没有userId可供使用,可以使用一个全局的key来代替,确保该key会随着页面的刷新而变化即可,比如可以用进入页面后的某个时间点的时间戳

  2. 清除旧的localStorage缓存,由于浏览器对localStorage的大小是有限制的,所以在发版后对于先前保存的数据应当予以清除

export function clearLocalStorageCache() {
    // 这个key是存储本地缓存版本号的
    const key = 'LOCALSTORAGE_CACHE_VERSION';
    // 获取当前的本地存储版本号
    const localVersionKey = LOCALSTORAGE_CACHE_VERSION;
    // 获取旧的本地存储版本号
    const storageLocalVersionKey = window['localStorage'].getItem(key);
    // 如果新旧版本号不一致,则需要清除旧的缓存数据,并重新设置版本号
    if(Number(storageLocalVersionKey) !== localVersionKey) {
        for( let key of Object.keys(window['localStorage']) ) {
            if(key.endsWith(storageLocalVersionKey)) {
                window['localStorage'].removeItem(key);
            }
        }
        window['localStorage'].setItem(key, localVersionKey);
    }
}

这个方法可以在进入页面时就调用,我这边是在main.js中调用的