使用axios结合access_token和refresh_token进行无感刷新

时间:2024-03-09 22:34:17
<script setup lang="ts"> import { RouterLink, RouterView } from 'vue-router' import HelloWorld from './components/HelloWorld.vue' import axios, { type InternalAxiosRequestConfig } from 'axios' import { ref } from 'vue' let isRefreshing = false // 标志是否正在刷新token let requestQueue: { config: InternalAxiosRequestConfig; resolve: any }[] = [] // 存放token失效的请求配置的promise的resolve方法 axios.interceptors.request.use((config) => { config.headers.Authorization = 'bearer ' + localStorage.getItem('access_token') || '' //拦截器添加token请求头 return config }) axios.interceptors.response.use( (res) => { return res }, async (err) => { const { config, response } = err if (response.status == 401 && !config.url.endsWith('/login')) { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve) => { requestQueue.push({ config, resolve }) // accessToken失效后并发请求时,都会失败,把所有的config存起来,刷新完token再请求 if (isRefreshing) { return } isRefreshing = true await refreshToken() // 使用refreshToken拿到新的有效的accessToken和refreshToken,存放到loalStorage中 isRefreshing = false for (const { resolve, config } of requestQueue) { resolve(axios(config)) //这里请求失败拿到请求的config,才能重发请求 } }) } return Promise.reject(err) } ) const refreshToken = async () => { const { data } = await axios.get('http://localhost:3000/refreshToken', { params: { refresh_token: localStorage.getItem('refresh_token') } }) if (data.accessToken && data.refreshToken) { localStorage.setItem('access_token', data.accessToken) localStorage.setItem('refresh_token', data.refreshToken) } } const testData1 = ref() const testData2 = ref() const query = async () => { axios.get('http://localhost:3000/test1').then((res) => { testData1.value = res.data }) axios.get('http://localhost:3000/test2').then((res) => { testData2.value = res.data }) } const login = async () => { const { data } = await axios.get('http://localhost:3000/login') localStorage.setItem('access_token', data.accessToken) localStorage.setItem('refresh_token', data.refreshToken) } </script> <template> <button @click="login">登录</button> <button @click="query()">请求</button> <div> <h1>{{ testData1 }}</h1> <h1>{{ testData2 }}</h1> </div> </template> <style scoped></style>