You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3选项式API:Axios缓存Rest API数据与避免重复请求方案

Vue 3选项式API中Axios缓存REST API数据并避免重复请求的方案

在Vue 3选项式API里,实现Axios请求数据的缓存并避免重复请求,核心思路是请求前先检查缓存,有数据直接用,无数据再发起请求并把结果存入缓存。下面分两种常见缓存场景给出具体实现:

一、内存缓存(会话级,页面刷新后失效)

适合不需要持久化的场景,比如单页应用内的临时缓存。

1. 组件内缓存实现

在组件内部维护缓存状态和请求锁,避免重复触发请求:

<template>
  <div>{{ cachedData ? JSON.stringify(cachedData) : '加载中...' }}</div>
</template>

<script>
import axios from 'axios'

export default {
  data() {
    return {
      cachedData: null,
      isFetching: false // 请求锁,防止同一时间重复发起请求
    }
  },
  async mounted() {
    await this.fetchDataWithCache()
  },
  methods: {
    async fetchDataWithCache() {
      // 先检查内存缓存
      if (this.cachedData) {
        console.log('使用内存缓存数据')
        return
      }
      // 检查是否已有请求在进行
      if (this.isFetching) return
      
      this.isFetching = true
      try {
        const response = await axios.get('https://api.example.com/data')
        this.cachedData = response.data
        console.log('请求成功,已存入内存缓存')
      } catch (error) {
        console.error('请求失败:', error)
      } finally {
        this.isFetching = false
      }
    }
  }
}
</script>

2. 全局内存缓存(多组件共享)

如果多个组件需要共用同一接口数据,可以封装一个全局缓存工具:

// utils/axiosCache.js
import axios from 'axios'

const memoryCache = new Map()
const pendingRequests = new Set()

export async function fetchWithMemoryCache(url) {
  // 检查缓存是否存在
  if (memoryCache.has(url)) {
    return memoryCache.get(url)
  }
  // 检查是否已有相同请求在处理
  if (pendingRequests.has(url)) {
    // 等待已有请求完成后返回缓存数据
    return new Promise(resolve => {
      const interval = setInterval(() => {
        if (memoryCache.has(url)) {
          clearInterval(interval)
          resolve(memoryCache.get(url))
        }
      }, 50)
    })
  }

  pendingRequests.add(url)
  try {
    const response = await axios.get(url)
    memoryCache.set(url, response.data)
    return response.data
  } catch (error) {
    throw error
  } finally {
    pendingRequests.delete(url)
  }
}

组件内使用示例:

<script>
import { fetchWithMemoryCache } from '@/utils/axiosCache'

export default {
  data() {
    return {
      cachedData: null
    }
  },
  async mounted() {
    try {
      this.cachedData = await fetchWithMemoryCache('https://api.example.com/data')
    } catch (error) {
      console.error(error)
    }
  }
}
</script>

二、浏览器本地缓存(持久化,页面刷新后仍保留)

用localStorage实现持久化缓存,建议加上过期时间避免缓存过期数据:

封装带过期时间的本地缓存请求

// utils/axiosLocalCache.js
import axios from 'axios'

const CACHE_KEY_PREFIX = 'api_cache_'

// 从localStorage读取缓存并检查有效期
function getLocalCache(key) {
  const cacheStr = localStorage.getItem(CACHE_KEY_PREFIX + key)
  if (!cacheStr) return null
  
  const cacheObj = JSON.parse(cacheStr)
  if (Date.now() > cacheObj.expireTime) {
    localStorage.removeItem(CACHE_KEY_PREFIX + key)
    return null
  }
  return cacheObj.data
}

// 将数据存入localStorage并设置过期时间
function setLocalCache(key, data, expireMinutes = 30) {
  const cacheObj = {
    data,
    expireTime: Date.now() + expireMinutes * 60 * 1000
  }
  localStorage.setItem(CACHE_KEY_PREFIX + key, JSON.stringify(cacheObj))
}

export async function fetchWithLocalCache(url, expireMinutes = 30) {
  const cacheKey = url // 可根据请求参数生成更唯一的key,比如`url+JSON.stringify(params)`
  const cachedData = getLocalCache(cacheKey)
  
  if (cachedData) {
    console.log('使用本地缓存数据')
    return cachedData
  }

  try {
    const response = await axios.get(url)
    setLocalCache(cacheKey, response.data, expireMinutes)
    console.log('请求成功,已存入本地缓存')
    return response.data
  } catch (error) {
    throw error
  }
}

组件内使用本地缓存请求

<template>
  <div>{{ cachedData ? JSON.stringify(cachedData) : '加载中...' }}</div>
</template>

<script>
import { fetchWithLocalCache } from '@/utils/axiosLocalCache'

export default {
  data() {
    return {
      cachedData: null
    }
  },
  async mounted() {
    try {
      // 设置缓存有效期为10分钟
      this.cachedData = await fetchWithLocalCache('https://api.example.com/data', 10)
    } catch (error) {
      console.error('请求失败:', error)
    }
  }
}
</script>

三、Axios拦截器全局实现缓存

如果想给所有GET请求统一加缓存逻辑,可以通过拦截器实现:

// axios.js
import axios from 'axios'

const memoryCache = new Map()
const pendingRequests = new Set()

const instance = axios.create({
  baseURL: 'https://api.example.com'
})

// 请求拦截器:检查缓存,存在则取消原请求返回缓存
instance.interceptors.request.use(config => {
  if (config.method?.toLowerCase() === 'get') {
    const cacheKey = config.url + JSON.stringify(config.params)
    if (memoryCache.has(cacheKey)) {
      const source = axios.CancelToken.source()
      config.cancelToken = source.token
      source.cancel('使用缓存数据,取消原请求')
      return Promise.resolve({ data: memoryCache.get(cacheKey) })
    }
    if (pendingRequests.has(cacheKey)) {
      const source = axios.CancelToken.source()
      config.cancelToken = source.token
      source.cancel('已有相同请求在处理,取消当前请求')
    } else {
      pendingRequests.add(cacheKey)
    }
  }
  return config
})

// 响应拦截器:将请求结果存入缓存
instance.interceptors.response.use(response => {
  if (response.config.method?.toLowerCase() === 'get') {
    const cacheKey = response.config.url + JSON.stringify(response.config.params)
    memoryCache.set(cacheKey, response.data)
    pendingRequests.delete(cacheKey)
  }
  return response
}, error => {
  if (axios.isCancel(error)) {
    console.log(error.message)
    return Promise.resolve({ data: memoryCache.get(error.config.url + JSON.stringify(error.config.params)) })
  }
  pendingRequests.delete(error.config.url + JSON.stringify(error.config.params))
  return Promise.reject(error)
})

export default instance

组件内使用封装好的Axios实例:

<script>
import axios from '@/axios'

export default {
  data() {
    return {
      cachedData: null
    }
  },
  async mounted() {
    try {
      const response = await axios.get('/data', { params: { id: 1 } })
      this.cachedData = response.data
    } catch (error) {
      console.error(error)
    }
  }
}
</script>

内容的提问来源于stack exchange,提问作者Uzzal Hossain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 22:45:33