axios 缓存 Token无痛刷新

参考链接

/*
 * @Author: zhang gen yuan
 * @Date: 2021-10-09 17:51:00
 * @Descripttion: 
 */
import axios from 'axios'
 
// 数据存储
export const cache = {
  data: {},
  set (key, data, bol = false) {
    if (bol) {
      localStorage.setItem(key, JSON.stringify(data))
    } else {
      this.data[key] = data
    }
  },
  get (key, bol = false) {
    if (bol) {
      return JSON.parse(localStorage.getItem(key))
    } else {
      return this.data[key]
    }
  },
  clear (key, bol = false) {
    if (bol) {
      localStorage.removeItem(key)
    } else {
      delete this.data[key]
    }
  }
}
 
// 建立唯一的key值
function buildUrl (url, params = {}) {
  const sortedParams = Object.keys(params).sort().reduce((result, key) => {
    result[key] = params[key]
    return result
  }, {})
 
  url += `?${JSON.stringify(sortedParams)}`
  return url
}
 
// 缓存,建议只给get加缓存
export default (options = {}) => config => {
  const { url, method, params, data } = config
  const { local = false } = options
  // 建立索引
  let index
  if (method === 'get') {
    index = buildUrl(url, params)
  } else {
    index = buildUrl(url, data)
  }
  const indexData = index + '-data'
  let response = cache.get(indexData, local)
  let responsePromise = cache.get(index)
  if (response) {
    return Promise.resolve(JSON.parse(JSON.stringify(response))) // 对象是引用,为了防止污染数据源
  } else if (!responsePromise) {
    responsePromise = (async () => {
      try {
        const response = await axios.defaults.adapter(config)
        cache.set(indexData, response, local)
        return Promise.resolve(JSON.parse(JSON.stringify(response))) // 同时发送多次一样的请求,没办法防止污染数据源,只有业务中去实现
      } catch (reason) {
        cache.clear(index, local)
        cache.clear(indexData)
        return Promise.reject(reason)
      }
    })()
 
    // put the promise for the non-transformed response into cache as a placeholder
    cache.set(index, responsePromise)
  }
  return responsePromise
}

使用

import axios from “axios”;
import cache from “./…/utils/axios”;

 axios.get("/api/blade-auth/oauth/captcha", {
        adapter: cache({
          local: false
        }),
      }).then(res=>{
        console.log(res)
      })
import axios from 'axios'

// 从localStorage中获取token
function getLocalToken () {
    const token = window.localStorage.getItem('token')
    return token
}

// 给实例添加一个setToken方法,用于登录后将最新token动态添加到header,同时将token保存在localStorage中
instance.setToken = (token) => {
  instance.defaults.headers['X-Token'] = token
  window.localStorage.setItem('token', token)
}

function refreshToken () {
    // instance是当前request.js中已创建的axios实例
    return instance.post('/refreshtoken').then(res => res.data)
}

// 创建一个axios实例
const instance = axios.create({
  baseURL: '/api',
  timeout: 300000,
  headers: {
    'Content-Type': 'application/json',
    'X-Token': getLocalToken() // headers塞token
  }
})

// 是否正在刷新的标记
let isRefreshing = false
// 重试队列,每一项将是一个待执行的函数形式
let requests = []

instance.interceptors.response.use(response => {
  const { code } = response.data
  if (code === 1234) {
    const config = response.config
    if (!isRefreshing) {
      isRefreshing = true
      return refreshToken().then(res => {
        const { token } = res.data
        instance.setToken(token)
        config.headers['X-Token'] = token
        config.baseURL = ''
        // 已经刷新了token,将所有队列中的请求进行重试
        requests.forEach(cb => cb(token))
        requests = []
        return instance(config)
      }).catch(res => {
        console.error('refreshtoken error =>', res)
        window.location.href = '/'
      }).finally(() => {
        isRefreshing = false
      })
    } else {
      // 正在刷新token,将返回一个未执行resolve的promise
      return new Promise((resolve) => {
        // 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
        requests.push((token) => {
          config.baseURL = ''
          config.headers['X-Token'] = token
          resolve(instance(config))
        })
      })
    }
  }
  return response
}, error => {
  return Promise.reject(error)
})

export default instance
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值