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
还没有评论,来说两句吧...