前端接口请求支持内容缓存和过期时间

前端接口请求支持内容缓存和过期时间

支持用户自定义缓存时间,在规则时间内读取缓存内容,超出时间后重新请求接口

首先封装一下 axios,这一步可做可不做。但是在实际开发场景中都会对 axios 做二次封装,我们在二次封装的 axios 基础上继续封装,增加支持缓存功能

request.js

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import cache from '@/plugins/cache'
import qs from 'qs'// 本地开发环境需要加请求头
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
axios.defaults.headers['lang'] = 'CN'
// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: process.env.VUE_APP_BASE_API,// 超时timeout: 100000,
})// request拦截器
service.interceptors.request.use((config) => {// 是否需要设置 tokenconst isToken = (config.headers || {}).isToken === false// 是否需要防止数据重复提交const isRepeatSubmit = (config.headers || {}).repeatSubmit === falseif (getToken() && !isToken) {config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改}// get请求映射params参数if (config.method === 'get' && config.params) {let url = config.url + '?' + qs.stringify(config.params)url = url.slice(0, -1)config.params = {}config.url = url}if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {const requestObj = {url: config.url,data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,time: new Date().getTime(),}const sessionObj = cache.session.getJSON('sessionObj')if (sessionObj === undefined || sessionObj === null || sessionObj === '') {cache.session.setJSON('sessionObj', requestObj)} else {// 忽略重复请求的地址const exUrls = []const s_url = sessionObj.url // 请求地址const s_data = sessionObj.data // 请求数据const s_time = sessionObj.time // 请求时间const interval = 3000 // 间隔时间(ms),小于此时间视为重复提交if (s_data === requestObj.data &&requestObj.time - s_time < interval &&s_url === requestObj.url &&!exUrls.includes(config.url)) {const message = '数据正在处理,请勿重复提交'return Promise.reject(new Error(message))} else {cache.session.setJSON('sessionObj', requestObj)}}}return config},(error) => {Promise.reject(error)}
)// 响应拦截器
service.interceptors.response.use((res) => {// 未设置状态码则默认成功状态const code = res.data.code || '0'// 获取错误信息const msg = res.data.message// 二进制数据则直接返回if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {return res.data}if (code === 401 || code === '10006') {MessageBox.confirm('登录状态已过期,请重新登录', '系统提示', {confirmButtonText: '重新登录',cancelButtonText: '取消',type: 'warning',}).then(() => {store.dispatch('LogOut').then(() => {location.href = '/login'})})} else if (code !== '0') {Message({message: msg || '接口请求异常',type: 'error',})return Promise.reject(new Error(msg))} else {return res.data}},(error) => {let { message } = errorif (message === 'Network Error') {message = '后端接口连接异常'} else if (message.includes('timeout')) {message = '系统接口请求超时'} else if (message.includes('Request failed with status code')) {message = '系统接口' + message.substr(message.length - 3) + '异常'}Message({message: message,type: 'error',duration: 5 * 1000,})return Promise.reject(error)}
)export default service

新建 catchAjax.js ,当我们想用接口缓存时,就用 catchAjax 方法,不想用时还用上面的 request 文件,互不影响

const cacheMap = new Map()
// 定义状态池
const statusMap = new Map()
// 回调callbackMap
const callbackMap = new Map()
// 引入axios
import myAxios from '@/utils/request'
// qs用于序列化对象,将对象序列化为用&拼接的参数
import qs from 'qs'// 一般只缓存GET接口
function generateCacheKey(request) {return request.url + '?' + qs.stringify(request.params)
}// 返回指定分钟后的时间戳 过期时间
function generateExpTime(minutes) {// 获取当前时间戳let now = new Date()// 添加分钟数now.setMinutes(now.getMinutes() + minutes)// 返回未来的时间戳return now.getTime()
}// 导出请求方法
export function cacheRequest(request) {if (request.method && request.method.toUpperCase() !== 'GET') {throw new Error('cacheRequest 仅支持GET请求')}if (request.expTime && !/^\d+$/.test(request.expTime)) {throw new Error('expTime 必须是正整数')}// 用当前请求的 url + 参数 来当做缓存的keyconst cacheKey = generateCacheKey(request)// 判断状态池中是否有数据if (statusMap.has(cacheKey)) {// 获取当前的状态const currentStatus = statusMap.get(cacheKey)// 如果接口已经在缓存中,则进入这里if (currentStatus === 'complete') {// 判断是否过期let nowTime = new Date().getTime()// 已经过期的数据不能从缓存中取,设置这个状态是pending,重新走接口if (nowTime >= cacheMap.get(cacheKey).expTime) {statusMap.set(cacheKey, 'pending')} else {// 没有过期则从缓存中返回数据return Promise.resolve(cacheMap.get(cacheKey)?.data)}}if (currentStatus === 'pending') {// 判断回调池中是否有数据return new Promise((resolve, reject) => {if (callbackMap.has(cacheKey)) {callbackMap.get(cacheKey).push({onSuccess: resolve,onError: reject,})} else {callbackMap.set(cacheKey, [{onSuccess: resolve,onError: reject,},])}})}}// 设置接口状态statusMap.set(cacheKey, 'pending')// 判断是否需要缓存,并且缓存池中有数据时,返回缓存池中的数据return myAxios(request).then((res) => {// 接口响应成功后吧当前的请求状态设置为complete,下次请求时就会走缓存,不会走网络statusMap.set(cacheKey, 'complete')// 往缓存中塞数据,同时设置过期时间cacheMap.set(cacheKey, {data: res,// 默认缓存5分钟expTime: generateExpTime(request.expTime || 5),})// 判断在接口响应期间是否有请求,如果有请求,则遍历所有的回调并执行if (callbackMap.has(cacheKey)) {callbackMap.get(cacheKey).forEach((callback) => {callback.onSuccess(res)})// 响应完数据后吧回调删除callbackMap.delete(cacheKey)}// 返回真实的接口数据return res}).catch((error) => {statusMap.delete(cacheKey)if (callbackMap.has(cacheKey)) {callbackMap.get(cacheKey).forEach((callback) => {callback.onError(error)})callbackMap.delete(cacheKey)}return Promise.resolve(error)})
}

使用方法

<template><div><el-button type="primary" @click="cacheAxios">测试</el-button></div>
</template><script>
import { cacheRequest } from '@/utils/catchAjax'const getArticleList = (params) => {return cacheRequest({url: 'http://localhost:10086/order/list',method: 'get',params,expTime: 1, // 缓存一分钟})
}export default {name: 'index',methods: {cacheAxios() {getArticleList({pageNum: 1,pageSize: 10,}).then((res) => {console.log(res)})},},
}
</script>

image-20231030181210907

我们在 1 分钟内连续点击按钮,发现只会走一次接口,但是控制台可以打印多次数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/157914.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s之亲和性、污点

目录 亲和性 键值运算关系 硬策略 软策略 Pod亲和性与反亲和性 污点(Taint) 和 容忍(Tolerations) 污点(Taint) 容忍(Tolerations) 维护操作 故障排除步骤 亲和性 官方介绍&#xff1a;https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-nod…

asp.net旅游交流管理信息系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net 旅游交流管理信息系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c# 语言开发 asp.net旅游交流网站1 应用技…

超声波俱乐部分享:百度世界大会点燃AI创业者新希望

10月22日&#xff0c;2023年第十三期超声波俱乐部内部分享会在北京望京举行。本期的主题是&#xff1a;百度世界大会点燃AI创业者新希望。 到场的嘉宾有&#xff1a;超声波创始人杨子超&#xff0c;超声波联合创始人、和牛商业创始人刘思雨&#xff0c;中国国际经济交流中心研…

性能测试 —— Jmeter日志查看与分析

一、Jmeter日志概览 Jmeter日志文件保存在bin目录中&#xff0c;名称为jmeter.log。我们可以在面板中直接察看日志&#xff0c;点击右上角黄色标志物可以打开日志面板&#xff0c;再次点击收起 另外&#xff0c;Jmeter可以很方便地设置日志输出级别&#xff1a; 通过这种方式修…

【牛客网】安全—加密和安全

每日一练 Day1&#xff1a; 1.信息安全的基本属性是&#xff08; D &#xff09; A.保密性 B.完整性 C.可用性&#xff0c;可靠性&#xff0c;可控性 D.A、B、C都是 信息安全的基本属性通常可以归纳为以下几个方面&#xff1a; 保密性&#xff08;Confidentiality&#xf…

mac下载安装jenkins

下载 https://get.jenkins.io/war/ 启动 使用命令行启动 java -jar jenkins.war 浏览器访问 IP:8080 或 localhost:8080 &#xff0c;对jenkins进行配置&#xff0c;刚开始需要输入密码 终端会展示密码和密码存放位置 jenkins插件下载地址&#xff0c; 下载后自行上传。 I…

企业多部门VLAN间互访部署实战

1. 二层VLAN技术部署回顾&#xff1b; 2. 三层交换机上如何部署VLAN&#xff1f; 3. 部署VLAN的过程中有哪些注意事项&#xff1f; -- VLAN技术 - 虚拟局域网 -- 局域网 - 通过交换机连接的网络 -- VLAN - 把一个大的局域网 做一个分割 -- 常见局域网的问题&a…

vue3的ref源码解析

ref的实现原理 一句话总结: ref本身是个函数&#xff0c;该函数返回一个createRef函数&#xff0c;createRef函数又返回一个“经过类RefImpl实例化”的对象。 详情介绍: ref函数接收我们传入的一个简单类型或复杂类型value&#xff0c;后又将value传递给createRef函数&#xf…

postman接口测试—Restful接口开发与测试

开发完接口&#xff0c;接下来我们需要对我们开发的接口进行测试。接口测试的方法比较多&#xff0c;使用接口工具或者Python来测试都可以&#xff0c;工具方面比如之前我们学习过的Postman或者Jmeter &#xff0c;Python脚本测试可以使用Requests unittest来测试。 测试思路…

webpack 高级

高级配置就是要进行 webpack 优化&#xff0c;让代码在编译、运行时性能更好 主要从以下角度去优化&#xff1a; 1、提升开发体验 2、提升打包构建速度 3、减少代码体积 4、优化代码运行性能 一、提升体验 1、SourceMap 为什么 打包出来的所有css和js合并成了一个文件&#…

“排队领奖,购物狂欢!开启全新商业模式

欢迎来到这个充满惊喜的商业模式——工会排队奖励模式&#xff01;在这个时代&#xff0c;你是否感到购物和消费的乐趣被平淡无奇的模式所限制&#xff1f;那么&#xff0c;这个全新的商业模式将带你进入一个充满刺激和惊喜的世界&#xff01; 想象一下&#xff0c;当你购物时&…

Panda3d 相机控制

Panda3d 相机控制 文章目录 Panda3d 相机控制Panda3d中的透视镜头和垂直镜头透视镜头垂直镜头 Panda3d 中用代码控制相机的移动用键盘控制相机的移动用鼠标控制相机的移动 Panda3d 把相机也当做是一个 PandaNode&#xff0c;因此可以向操作其他节点对其进行操作。 真正的相机是…