NUXT 3中使用useFetch组合式函数实现失败请求重试
Nuxt3 中实现 useFetch 自动刷新 Token 并重试请求
基于你已有的自定义useCustomFetch组合式,我们可以通过添加响应拦截逻辑,实现 Token 过期时自动刷新并重试原请求的功能,核心是处理401错误、避免并发重复刷新、重试请求这几个关键点。
实现步骤与代码示例
修改你的composables/useCustomFetch.ts,加入以下逻辑:
// composables/useCustomFetch.ts import type { UseFetchOptions } from 'nuxt/app' import { useAuthStore } from '~/stores/auth' // 假设用Pinia管理Auth状态 import { navigateTo } from 'nuxt/app' // 全局锁:防止多个并发请求重复触发Token刷新 let isRefreshing = false // 存储等待Token刷新后重试的请求队列 let refreshQueue: Array<() => void> = [] export function useCustomFetch<T>(url: string, options: UseFetchOptions<T> = {}) { const authStore = useAuthStore() const currentToken = authStore.getToken // 默认配置:自动携带Authorization头 const defaultOptions: UseFetchOptions<T> = { headers: currentToken ? { Authorization: `Bearer ${currentToken}` } : {}, // 响应错误拦截器 onResponseError({ response, options }) { // 仅处理Token过期导致的401,排除刷新Token的请求本身(避免死循环) if (response.status === 401 && url !== '/api/auth/refresh') { // 如果正在刷新Token,将当前请求加入队列等待重试 if (isRefreshing) { return new Promise(resolve => { refreshQueue.push(() => { // 更新请求头的Token options.headers = { ...options.headers, Authorization: `Bearer ${authStore.getToken}` } // 重试请求 resolve(useCustomFetch(url, options)) }) }) } isRefreshing = true // 发起Token刷新请求 return useFetch('/api/auth/refresh', { method: 'POST', body: { refreshToken: authStore.getRefreshToken } }).then(async (refreshResult) => { if (!refreshResult.error.value) { const newToken = refreshResult.data.value?.accessToken const newRefreshToken = refreshResult.data.value?.refreshToken // 更新本地存储的Token authStore.updateToken(newToken, newRefreshToken) // 更新当前请求的Authorization头,并重试 options.headers = { ...options.headers, Authorization: `Bearer ${newToken}` } const retryResult = await useCustomFetch(url, options) // 执行队列中所有等待的请求 refreshQueue.forEach(cb => cb()) refreshQueue = [] return retryResult } else { // Token刷新失败,跳转登录页 await navigateTo('/login') return Promise.reject(refreshResult.error.value) } }).finally(() => { // 释放刷新锁 isRefreshing = false }) } } } // 合并用户传入的配置与默认配置 const mergedOptions = { ...defaultOptions, ...options } return useFetch(url, mergedOptions) }
关键细节说明
- 并发请求处理:通过
isRefreshing锁和refreshQueue队列,确保多个请求同时遇到401时,只触发一次Token刷新,所有等待的请求在刷新完成后统一重试。 - 避免死循环:判断当前请求不是刷新Token的接口,防止刷新接口本身返回401时无限重试。
- 状态更新:刷新成功后,更新Auth状态中的Token,确保后续请求自动携带新Token。
- 失败降级:如果Refresh Token也过期(刷新接口返回错误),直接跳转登录页,引导用户重新授权。
适配调整
- 如果你的项目不用Pinia,可替换为
useCookie存储Token和Refresh Token,比如:const token = useCookie('access_token') const refreshToken = useCookie('refresh_token') - 根据后端实际接口调整刷新Token的接口地址、请求方法和参数格式。
- 部分后端会返回特定错误码标识Token过期,可在
onResponseError中增加对响应体错误码的判断,而非仅依赖401状态码。
内容的提问来源于stack exchange,提问作者Praveen
相关产品推荐
相关产品推荐

