vue3 uniapp uview无感刷新token

5 篇文章 0 订阅
文章展示了在uniapp和vue3项目中如何使用http拦截器处理请求,当接收到401错误时自动刷新token并重试请求。通过设置请求和响应拦截器,检测token状态,刷新后更新请求头并重试队列中的请求。
摘要由CSDN通过智能技术生成

废话不多说直接上代码,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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值