美文网首页
Axios+Cache

Axios+Cache

作者: 萘小蒽 | 来源:发表于2023-09-08 20:53 被阅读0次

    使用某种方法缓存特定接口返回的固定数据,避免重复请求。
    比如下面的代码,将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,
      });
    }
    

    相关文章

      网友评论

          本文标题:Axios+Cache

          本文链接:https://www.haomeiwen.com/subject/qqydvdtx.html