使用某种方法缓存特定接口返回的固定数据,避免重复请求。
比如下面的代码,将axios二次封装。
Cache.js
// import { showDialog } from 'vant';
let CACHES = {}
export default class Cache {
constructor(axios) {
this.axios = axios
if (!this.axios) throw new Error('缺少axios实例')
this.cancelToken = axios.CancelToken
this.options = {}
}
use(options) {
let defaults = {
expire: 3600000, // 过期时间 默认一分钟
storage: false, // 是否开启缓存
storage_expire: 3600000, // 本地缓存过期时间 默认一小时
instance: this.axios, // axios的实例对象 默认指向当前axios
requestConfigFn: null, // 请求拦截的操作函数 参数为请求的config对象 返回一个Promise
responseConfigFn: null // 响应拦截的操作函数 参数为响应数据的response对象 返回一个Promise
}
this.options = Object.assign(defaults, options)
this.init()
// if (options && !options.instance) return this.options.instance
}
init() {
let options = this.options
if (options.storage) {
// 如果开启本地缓存 则设置一个过期时间 避免时间过久 缓存一直存在
this._storageExpire('expire').then(() => {
if (localStorage.length === 0) CACHES = {}
else mapStorage(localStorage, 'get')
})
}
this.request(options.requestConfigFn)
this.response(options.responseConfigFn)
}
request(cb) {
let options = this.options
options.instance.interceptors.request.use(async config => {
// 判断用户是否返回 config 的 promise
let newConfig = cb && (await cb(config))
config = newConfig || config
if (config.cache) {
// console.log(config, '缓存');
let source = this.cancelToken.source()
config.cancelToken = source.token
let data = CACHES[config.url]
let expire = getExpireTime()
// 判断缓存数据是否存在 存在的话 是否过期 没过期就返回
if (data && expire - data.expire < this.options.expire) {
source.cancel(data)
}
}
return config
})
}
response(cb) {
this.options.instance.interceptors.response.use(
async response => {
let newResponse = cb && (await cb(response))
response = newResponse || response
if (response.config.cache) {
let data = {
expire: getExpireTime(),
data: response
}
CACHES[`${response.config.url}`] = data
if (response.config.cache) mapStorage(CACHES)
}
return response.data
},
error => {
// 返回缓存数据
// if (error) {
// showDialog({
// title: '提示',
// message: '网络异常,请稍后重试',
// })
// }
if (this.axios.isCancel(error)) {
return Promise.resolve(error.message.data.data)
}
return Promise.reject(error)
}
)
}
// 本地缓存过期判断
_storageExpire(cacheKey) {
return new Promise(resolve => {
let key = getStorage(cacheKey)
let date = getExpireTime()
if (key) {
// 缓存存在 判断是否过期
let isExpire = date - key < this.options.storage_expire
// 如果过期 则重新设定过期时间 并清空缓存
if (!isExpire) {
removeStorage()
}
} else {
setStorage(cacheKey, date)
}
resolve()
})
}
}
/**
* caches: 缓存列表
* type: set->存 get->取
*/
function mapStorage(caches, type = 'set') {
Object.entries(caches).map(([key, cache]) => {
if (type === 'set') {
setStorage(key, cache)
} else {
// 正则太弱 只能简单判断是否是json字符串
try {
CACHES[key] = JSON.parse(cache)
} catch (error) {
// console.error(`Invalid JSON format: ${error}`)
CACHES[key] = cache
}
}
})
}
// 清除本地缓存
function removeStorage() {
localStorage.clear()
}
// 设置缓存
function setStorage(key, cache) {
if (typeof cache === 'object') cache = JSON.stringify(cache)
localStorage.setItem(key, cache)
}
// 获取缓存
function getStorage(key) {
let data = localStorage.getItem(key)
return JSON.parse(data)
}
// 设置过期时间
function getExpireTime() {
return new Date().getTime()
}
requset.js
import axios from 'axios'
import Cache from './Cache'
import { showToast, showConfirmDialog, ToastOptions } from 'vant';
import router from '@/router';
import 'vant/es/dialog/style';
import { stringify } from "qs";
const instance = axios.create({
// baseURL: '/api',
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 10000,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild',
'Access-Control-Allow-Credentials': 'true',
'X-Requested-With': 'XMLHttpRequest',
},
withCredentials: true,
paramsSerializer: {
serialize: stringify // or (params) => Qs.stringify(params, {arrayFormat: 'brackets'})
}
});
let cache = new Cache(axios) // 将当前 axios 对象传入 Cache 中
cache.use({
expire: 10000,
storage: true,
instance, // 如果有自定义axios实例 比如上面的instance 需要将其传入instance 没有则不传
requestConfigFn: (config: { headers: { Authorization: string | null; }; }) => {
// 请求拦截自定义操作
if (config.headers) {
config.headers.Authorization = localStorage.getItem('token')
}
// 需要将config对象通过 Promise 返回 cache 中 也可以使用new Promise的写法
return Promise.resolve(config)
},
responseConfigFn: (res: { data: { code: number; msg: any; localMessage: string | ToastOptions | undefined; }; }) => {
// 响应拦截的自定义操作
if (res.data.code) {
if (res.data.code === 10005) {
// showToast('登录已过期,请重新登录!')
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
showConfirmDialog({
title: '提示',
message: '登录已过期,请重新登录!',
})
.then(() => {
router.push('/login')
})
.catch(() => {
// on cancel
})
} else if (res.data.code === 200) {
return Promise.resolve(res)
} else if (res.data.code === 10007) {
localStorage.removeItem('token')
localStorage.removeItem('userInfo')
showConfirmDialog({
title: '提示',
message: '登录已过期,请重新登录!',
})
.then(() => {
router.push('/login')
})
.catch(() => {
// on cancel
})
}else {
if(res.data.msg){
showToast(res.data.msg)
}
if(res.data.localMessage){
showToast(res.data.localMessage)
}
return Promise.resolve(res)
}
}
}
})
export default instance
api调用
export function getStudios(data){
return request({
url: "/home/video/getStudios/v2",
method: "post",
cache: true,
data
});
}
export function getDailyAttendanceNotice(){
return request({
url: "/home/getDailyAttendanceNotice",
method: "get",
cache: true,
});
}
网友评论