前言?
继上一篇实现防止重复网络,这添加一个本地缓存功能
实现思路 ?
判断接口是否有配置cache
属性
-
如果有
cache
属性,查看当前请求地址是否有- 没有数据正常发送请求
- 本地有数据查看过期时间是否过期
- 过期正常发送请求
- 没有过期直接返回本地数据
Promise.resolve(data)
-
没有
cache
属性- 正常发送请求
一、配置请求接口 ?
平时写请求接口api
import { httpRequest } from '@/plugin/axios'; // axios.js 文件
// 请求接口
export function getInit(params) {
return httpRequest({
url: '/api/xxx/xxx',
method: 'get',
params,
cache: { //+ 在这里配置一个属性用于是否开启缓存
m: 5, // + 缓存 5分钟
h: 1, // + 缓存1个小时
}
})
}
二、使用axios库文件进行配置 ?
axios.js
配置文件
import axios from 'axios';
import { getRequest, HttpResponse, httpError } from './cacheHttp.js'; // 这里就是我们要实现的逻辑文件
// 里面做一些请求拦截,响应拦截操作 具体查看axios文档
const service = axios.create({
baseURL: 'xxx/xxx',
});
// 请求拦截器
service.interceptors.request.use(config => {}, error => {})
// 响应拦截器
service.interceptors.response.use(response => {
HttpResponse(response); // + 2.响应请求回来执行
}, error => {
httpError(); // + 3. 错误处理
})
export function http(config) { // => 这里config就是传递的请求配置参数
return getRequest(config, service); // + 1.在这里做一些逻辑操作
}
三、实现本地缓存配置文件 ?
?1.先封装一下localStorage
文件
localStorage.js
配置文件
/**
* 职责: localStorage
*/
// 存入localStorage
export function setItemLocalStorage(key: string, data: any) {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch (e) {
// (谷歌, 360, 火狐, ie)本地存储满了抛出的错误
if (e.name === 'QuotaExceededError') {
// 本地存储满了,清空本地存储
removeItemStorage(key);
localStorage.setItem(key, JSON.stringify(data));
}
}
}
// 获取localStorage
export function getItemLocalStorage(key: string) {
const res = localStorage.getItem(key);
try {
return JSON.parse(res);
} catch (e) {
throw new TypeError(`fail to get is ${key} localStorage, info ${e}`)
}
}
// 删除localStorage
export function removeItemStorage(key: string) {
localStorage.removeItem(key);
}
// 清空所有localStorage
export function clearLocalStorage() {
localStorage.clear();
}
2.工具函数封装一下
utils.js
export const isObj = obj => Object.prototype.toString.call(obj) === '[object Object]' && Object.keys(obj).length > 0;
export const isArray = arr => Object.prototype.toString.call(arr) === '[object Array]' && arr.length > 0;
export const CACHEKEY = 'CACHE_DATA'; // 存入本地数据的key
/**
* @param {Object} obj
*/
export const getformatObjVal = (obj) => {
obj = typeof obj === 'string' ? JSON.parse(`${obj}`) : obj;
let str = [];
for (let p in obj) {
if (obj.hasOwnProperty(p) && p !== '_t') {
const item = obj[p] === null ? '' : obj[p]; // 处理null
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(item));
}
}
return str.join('&');
}
export const getUrl = (config) => {
// 暂时就在get请求、post请求的时候进行操作
const { method = 'get', params = {}, url = '', baseURL = '' } = config;
const urlVal: string = url.replace(baseURL, '');
return `${urlVal}?${method === 'get' ? getformatObjVal(params) : 'post'}`;
}
3.下面我就可以开始写逻辑函数啦
cacheHttp.js
配置文件
(1)初步实现存入数据到本地localStorage
/**
* 职责: 缓存请求数据
*/
import { getUrl, isObj, CACHEKEY } from '../utils';
import { setItemLocalStorage, getItemLocalStorage } from '../utils/localStorage';
export default class CacheRequet {
getTime(time) {
const { h = 0, m = 0 } = time;
const _t = h * 3600 * 1000 + m * 60 * 1000; // 所有时间戳
return _t + Date.now();
}
// 获取过期时间
getExpirationTime(config) {
const { cache } = config;
if (isObj(cache)) {
return this.getTime(cache);
}
if (typeof cache === 'boolean') {
// 默认开启五分钟
return this.getTime({ m: 5 });
}
return Date.now(); // 存入当前时间
}
setStorageData(data, config) {
const urlKey = getUrl(config); // 获取url地址作为每一个key
// 1.先取出所有的数据 然后在把当前的值塞入进去
const mapData = getItemLocalStorage(CACHEKEY); // 本地所有数据
if (!mapData) {
const params = {};
params[urlKey] = data;
setItemLocalStorage(CACHEKEY, params); // 存入本地
return;
}
mapData[urlKey] = data; // 赋值给当前对象
setItemLocalStorage(CACHEKEY, mapData); // 存入本地
}
// 保存数据到本地
setCacheData(response) {
const { data, config } = response;
const { cache } = config;
if (!cache) return; // 不要开启缓存 直接返回
this.setStorageData({
data,
expirationTime: this.getExpirationTime(config) // 过期时间
}, config)
}
}
const cacheRequst = new CacheRequet();
// 响应请求
export const HttpResponse = (response) => {
cacheRequst.setCacheData(response);
};
到这里我们就可以存入本地数据;?
import { httpRequest } from '@/plugin/axios'; // axios.js 文件
// 请求接口
export function getInit(params) {
return httpRequest({
url: '/api/xxx/xxx',
method: 'get',
params,
cache: { //+ 在这里配置一个属性用于是否开启缓存
m: 5, // + 缓存 5分钟
}
})
}
本地缓存数据图:
接下来继续实现如果获取本地数据并返回给页面。
(2)实现获取本地数据
导出接口
判断本地有没有缓存:
getCacheData
方法有值就返回本地缓存值
,没有本地缓存返回false
1.如果有值就直接拿去本地缓存的数据,返回一个成功的Promise.resolve
2.本地没有缓存或过期时间过期,正常发送请求
import cacheHttp from './cacheRequest/index';
/**
* @param {Function} http 请求体
* @param {Object} options 打印控制台信息
*/
export const getRequest = (http, options) => {
return function (config) {
const cacheData = cacheRequst.getCacheData(config);
if (cacheData) {
return Promise.resolve(cacheData); // 返回本地缓存数据
}
// 2.返回http方法
return getHttp.getRequest(config); // 正常发送请求
};
}
cacheRequest.js
发送请求前先拦截请求,获取本地缓存数据,
- 如果本地缓存有数据并过期时间没有过期,则返回本地数据
- 没有本地数据直接发起新的请求
/**
* 职责: 缓存请求数据
*/
import { getUrl, isObj, CACHEKEY } from '../utils';
import { setItemLocalStorage, getItemLocalStorage } from '../utils/localStorage';
export default class CacheRequet {
constructor() {
this.response = Object.create(null);
this.config = Object.create(null);
}
// ... 设置本地数据函数就省略
// 获取本地缓存数据
getCacheData(config) {
const { cache } = config;
if (!cache) return; // 不要开启缓存 直接返回
const localData = getItemLocalStorage(CACHEKEY); //1. 获取本地所有数据
if (!localData) return false; //2. 没有数据直接返回
const urlKey = getUrl(config); // 获取url地址作为每一个key
console.log(localData); // 打印数据看看
}
}
打印控制台看看本地缓存出来的数据:
接下来就可以判断过期时间和当前时间进行比较:
// 获取本地缓存数据
getCacheData(config) {
const { cache } = config;
if (!cache) return; // 不要开启缓存 直接返回
const localData = getItemLocalStorage(CACHEKEY); //1. 获取本地所有数据
if (!localData) return false; //2. 没有数据直接返回
const urlKey = getUrl(config); // 获取url地址作为每一个key
// 3.判断当前数据是否过期
const { data = {}, expirationTime = 0 } = localData[urlKey] || {};
if (Date.now() >= expirationTime) {
// 时间过期
return false;
}
// 4.时间没有过期,返回本地数据
return data
}
到这一步就实现了本地缓存功能啦?
4.完整缓存文件代码
cacheRequest.js
/**
* 职责: 缓存请求数据
*/
import * as interFace from '../utils/interface';
import { getUrl, isObj, CACHEKEY } from '../utils';
import { setItemLocalStorage, getItemLocalStorage } from '../utils/localStorage';
export default class CacheRequet {
getTime(time) {
const { h = 0, m = 0 } = time;
const _t = h * 3600 * 1000 + m * 60 * 1000; // 所有时间戳
return _t + Date.now();
}
// 获取过期时间
getExpirationTime(config) {
const { cache } = config;
if (isObj(cache)) {
return this.getTime(cache);
}
if (typeof cache === 'boolean') {
// 默认开启五分钟
return this.getTime({ m: 5 });
}
return Date.now(); // 存入当前时间
}
setStorageData(data, config) {
const urlKey = getUrl(config); // 获取url地址作为每一个key
// 1.先取出所有的数据 然后在把当前的值塞入进去
const mapData = getItemLocalStorage(CACHEKEY); // 本地所有数据
if (!mapData) {
const params = {};
params[urlKey] = data;
setItemLocalStorage(CACHEKEY, params); // 存入本地
return;
}
mapData[urlKey] = data; // 赋值给当前对象
setItemLocalStorage(CACHEKEY, mapData); // 存入本地
}
// 保存数据到本地
setCacheData(response) {
const { data, config } = response;
const { cache } = config;
if (!cache) return; // 不要开启缓存 直接返回
this.setStorageData({
data,
expirationTime: this.getExpirationTime(config) // 过期时间
}, config)
}
// 获取本地缓存数据
getCacheData(config) {
const { cache } = config;
if (!cache) return; // 不要开启缓存 直接返回
const localData = getItemLocalStorage(CACHEKEY); //1. 获取本地所有数据
if (!localData) return false; //2. 没有数据直接返回
const urlKey = getUrl(config); // 获取url地址作为每一个key
// 3.判断当前数据是否过期
const { data = {}, expirationTime = 0 } = localData[urlKey] || {};
if (expirationTime <= Date.now()) {
// 时间过期
return false;
}
// 4.时间没有过期,返回本地数据
return data
}
}
导出文件index.js
import cacheHttp from './cacheRequest/index';
const cacheRequst = new cacheHttp();
/**
* @param {Function} http 请求体
* @param {Object} options 打印控制台信息
*/
export const getRequest = (http: any, options?) => {
return function (config) {
const cacheData = cacheRequst.getCacheData(config);
if (cacheData) {
return Promise.resolve(cacheData); //1. 返回本地缓存数据 !!!
}
// 本地没有缓存数据 正常发送请求
// 2.返回http方法
return http(config);
};
}
// 响应请求
export const HttpResponse = (response) => {
cacheRequst.setCacheData(response);
return response;
};
这里我使用的axios库(按自己场景配置):
axios.js
import axios from 'axios';
import { getRequest, HttpResponse, } from './cacheHttp.js'; // 这里就是我们要实现的逻辑文件
// 里面做一些请求拦截,响应拦截操作 具体查看axios文档
const service = axios.create({
baseURL: 'xxx/xxx',
});
// 请求拦截器
service.interceptors.request.use(config => {}, error => {})
// 响应拦截器
service.interceptors.response.use(response => {
return HttpResponse(response); // + 2.响应请求回来执行
})
export function http(config) { // => 这里config就是传递的请求配置参数
return getRequest(config, service); // + 1.在这里做一些逻辑操作
}
以上就实现本地缓存啦。
注意⚠️: 如果直接配置了一些响应拦截器相关,走本地缓存获取数据不会走响应拦截器,会直接返回本地缓存的数据。 后期可以可以加入一些配置。 后期在配置项加入一个回调函数解决。
源码github
可以直接导入项目使用。如果觉得我的思路有用的话不妨点个赞?。谢谢!
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!