accessToken过期后使用refreshToken调用刷新 token 接口去获取新的accessToken
js
复制代码
// tokenManager.js
class TokenManager {
constructor() {
// 用于存储刷新token的promise,防止并发刷新
this.promise = null
}
/**
* 设置访问token
* @param {string} token
*/
setToken(token) {
localStorage.setItem('accessToken', token)
}
/**
* 获取刷新token
* @returns {string|null}
*/
getRefreshToken() {
return localStorage.getItem('refreshToken')
}
/**
* 移除所有token信息
*/
removeToken() {
localStorage.removeItem('accessToken')
localStorage.removeItem('refreshToken')
localStorage.removeItem('name')
}
/**
* 调用接口刷新token
* @returns {Promise<Response>}
*/
async refreshAccessToken() {
// 这里是刷新token的接口
const response = await fetch('/api/v3/Logon/getRefreshUserToker', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Refresh-Token': 'true',
},
body: JSON.stringify({
refreshToken: this.getRefreshToken(),
name: localStorage.getItem('name'),
}),
})
return response.json()
}
/**
* 获取token,如果正在刷新则返回同一个promise
* @returns {Promise<boolean>} 刷新成功返回true,失败返回false
*/
refreshToken() {
if (this.promise) return this.promise
this.promise = new Promise(resolve => {
this.refreshAccessToken()
.then(res => {
if (res.code === 0) {
this.setToken(res.accessToken)
resolve(true)
} else {
this.removeToken()
resolve(false)
}
})
.catch(err => {
console.error('Refresh token failed', err)
this.removeToken()
resolve(false)
})
})
this.promise.finally(() => {
this.promise = null
})
return this.promise
}
}
const tokener = new TokenManager()
export default tokener
在响应拦截中使用刷新token
js
复制代码
// request.js
import tokener from './tokenManager.js'
/**
* 请求封装
* @param {string} url
* @param {RequestInit} options
* @returns {Promise<any>}
*/
const request = async (url, options = {}) => {
// 合并默认配置
const config = {
...options,
headers: {
'Content-Type': 'application/json',
...options.headers,
},
}
// 添加token
const token = localStorage.getItem('accessToken')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
try {
const response = await fetch(url, config)
// 拦截 401 未授权,且不是刷新token的请求
if (response.status === 401 && !config.headers['X-Refresh-Token']) {
// 尝试刷新token
const isRefreshSuccess = await tokener.refreshToken()
if (isRefreshSuccess) {
// 刷新成功,重试原请求
// 更新header中的token
const newToken = localStorage.getItem('accessToken')
config.headers['Authorization'] = `Bearer ${newToken}`
// 重新发起请求
return fetch(url, config).then(res => res.json())
} else {
// 刷新失败,抛出错误或跳转登录
throw new Error('Token refresh failed')
// window.location.href = '/login'
// 可以记录当前页面,重新登陆后跳转到当前页面
// localStorage.setItem('redirectUrl', window.location.href)
}
}
return response.json()
} catch (error) {
console.error('Request failed:', error)
throw error
}
}
export default request