废话不多说直接上代码,uniapp+uview版本
import { refreshToken } from '@/api/login.js' //接口请求
// 是否正在刷新的标记
let isRefreshing = false
// 重试队列,每一项将是一个待执行的函数形式
let requests = []
// 此vm参数为页面的实例,可以通过它引用vuex中的变量
module.exports = (vm) => {
// 初始化请求配置
uni.$u.http.setConfig((config) => {
/* config 为默认全局配置*/
config.baseURL = 'https://aaa.com'; /* 根域名 */
return config
})
// 请求拦截
uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
// 添加请求头
config.header['tenant-id'] = '1'
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
config.data = config.data || {}
// 根据custom参数中配置的是否需要token,添加对应的请求头
const token = uni.getStorageSync('token');
if (token.accessToken) {
// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
config.header.Authorization = 'Bearer ' + token.accessToken
}
return config
}, config => { // 可使用async await 做异步操作
return Promise.reject(config)
})
// 响应拦截
uni.$u.http.interceptors.response.use(async (response) => {
/* 对响应成功做点什么 可使用async await 做异步操作*/
const data = response.data // 因为我这里后端做了深层嵌套返回数据,所以需要先拿到底层
// 无感刷新token
if (data.code === 401) {
//token无效或已过期
if (!isRefreshing) {
// 是否已经执行刷新
isRefreshing = true
let token = uni.getStorageSync('token') // 获取到过期的token,我这里是个对象
// 我是采用了封装请求的方式,这个无所谓,只要请求就好了
let res = await refreshToken({
refreshToken: token.refreshToken // 刷新token的令牌存在token的对象里面,需要传给后端
})
// 请求成功,开启刷新标识
isRefreshing = false
// 请求成功把新的token存到本地
uni.setStorageSync('token', res)
// 已经刷新了token,将所有队列中的请求进行重试
requests.forEach((item) => item(res.accessToken))
requests = []
}
// 每个接口请求都要存入队列,等刷新完以后都需要执行
return new Promise((resolve) => {
// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
requests.push((token) => {
//这一步一定要有,刷新token,因为存入的信息是旧的token
response.config.header = {
Authorization: "Bearer " + token,
}
resolve(uni.$u.http.request(response.config)) //执行请求
})
})
}
return data.data === undefined ? {} : data.data
}, (response) => {
// 对响应错误做点什么 (statusCode !== 200)
return Promise.reject(response)
})
}
下面的是vue3版本的无感token
import axios from 'axios'
import { ElMessage } from 'element-plus'
import router from '@/router/index.js'
import { refreshToken } from '@/api/login'
// 是否正在刷新的标记
let isRefreshing = false
// 重试队列,每一项将是一个待执行的函数形式
let requests = []
console.log(import.meta.env.VITE_BASE_URL)
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_URL, //获取生产或开发环境
timeout: 10000,
headers: {
// 设置后端需要的传参类型
'Content-Type': 'application/json;charset=utf-8',
'X-Requested-With': 'XMLHttpRequest',
Authorization: 'Bearer test1',
'tenant-id': 1
}
})
// request拦截器
service.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
if (sessionStorage.getItem('token')) {
config.headers.Authorization =
'Bearer ' + JSON.parse(sessionStorage.getItem('token'))?.accessToken || ''
}
return config
},
(error) => {
// 对请求错误做些什么
console.log(error)
return Promise.reject(error)
}
)
// response响应拦截器
service.interceptors.response.use(
async (response) => {
// 结构一层数据
const dataAxios = response.data
// 自定义参数,这里根据自己需求定义
if (dataAxios.msg == '刷新令牌已过期' || dataAxios.msg == '无效的刷新令牌') {
ElMessage.error('登录凭证过期,请重新登陆') //错误信息
sessionStorage.clear() // 删除缓存
isRefreshing = false // 请求成功,开启刷新标识
requests = [] // 置空
router.push('/login')
return false
}
// 无感刷新token
if (dataAxios.code === 401) {
//token无效或已过期
if (!isRefreshing) {
// 是否已经执行刷新
isRefreshing = true
const token = JSON.parse(sessionStorage.getItem('token'))
// 请求新的token
const res = await refreshToken({
refreshToken: token?.refreshToken
})
// 请求成功,开启刷新标识
isRefreshing = false
sessionStorage.setItem('token', JSON.stringify(res))
// 已经刷新了token,将所有队列中的请求进行重试
requests.forEach((item) => item(res?.accessToken))
requests = []
}
return new Promise((resolve) => {
// 将resolve放进队列,用一个函数形式来保存,等token刷新后直接执行
requests.push((token) => {
response.config.header = {
Authorization: 'Bearer ' + token
}
resolve(service(response.config)) //执行请求
})
})
}
// 错误信息
if (!dataAxios.data && dataAxios.code != 0) {
ElMessage.error(dataAxios.msg)
}
return dataAxios.data
},
(error) => {
console.log(error)
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
}
)
export default service