You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于ofetch的Nuxt API客户端实现401刷新Token后重试请求,但页面无法获取重试请求返回数据的问题

基于ofetch的Nuxt API客户端实现401刷新Token后重试请求,但页面无法获取重试请求返回数据的问题

看起来你遇到的核心问题是重试请求的结果没正确传递回页面,同时刷新Token的请求还被自己的拦截器干扰了,我来帮你一步步梳理和修复:

首先拆解下你代码里的几个关键问题:

  1. Refresh请求被拦截器“坑”了
    你现在用modules.auth.refresh发起刷新请求,但这个方法是基于带拦截器的apiFetcher创建的——而apiFetcher的onRequest钩子会自动给所有请求加上Authorization: Bearer {旧的accessToken}头。但刷新Token的接口根本不需要旧的accessToken,反而这个无效的Token会被后端直接拒绝,触发401进入catch块跳转到登录页,导致你的重试逻辑根本没机会执行。

  2. 重试请求的上下文传递不完整
    就算refresh请求成功了,你直接替换options.headers的方式可能会丢失原请求的其他头信息,导致重试请求不符合后端要求。

接下来是具体的修复方案:

步骤1:绕开拦截器发起Refresh请求

不要用带钩子的apiFetcher发refresh请求,直接用原始的$fetch,避免自动添加无效的Authorization头:

async onResponseError({ request, response, options }) {
  if (response.status === 401) {
    try {
      // 直接用原始$fetch发起refresh请求,绕开我们的拦截器
      const newTokens = await $fetch('/auth/refresh', {
        baseURL: nuxtApp.$config.public.apiBase,
        method: 'POST',
        body: { refresh_token: refreshTokenCookie.value }
      })

      // 更新Cookie和状态管理里的Token
      accessTokenCookie.value = newTokens.access_token
      refreshTokenCookie.value = newTokens.refresh_token
      authStore.setAccessToken(newTokens.access_token)
      authStore.setRefreshToken(newTokens.refresh_token)

      // 合并原请求的headers,只更新Authorization
      options.headers = new Headers({
        ...options.headers,
        'Authorization': `Bearer ${newTokens.access_token}`
      })

      // 重试原请求并返回结果,让最初的await能拿到重试后的响应
      return apiFetcher(request, options)
    } catch (error) {
      // 注意路径要加斜杠,避免匹配错误
      if (route.path !== '/auth') {
        navigateTo('/auth')
      }
      // 抛出错误,让原请求的调用链能捕获到问题
      throw error
    }
  }
}

步骤2:确保HttpFactory的调用逻辑正确

检查你的HttpFactory的call方法,确保它正确传递了请求选项,比如默认是GET请求,不会意外修改请求方法:

import type { FetchOptions } from 'ohmyfetch'

class HttpFactory {
  constructor(private readonly $fetch: typeof $fetch) {}

  protected call(resource: string, options: FetchOptions = {}) {
    // 保留原请求的所有选项,只拼接资源路径
    return this.$fetch(resource, options)
  }
}

步骤3:给useAsyncData加错误排查(可选)

为了更清晰地定位问题,可以给页面的useAsyncData加上错误处理,看看请求是不是真的失败了:

const { data: categories, error } = useAsyncData('categories', async () => {
  return await $api.category.getAll()
})

// 控制台打印错误,方便排查
if (error.value) {
  console.error('获取分类失败:', error.value)
}

这样修改后,你的refresh请求不会被自己的拦截器干扰,能正常拿到新Token,重试请求的结果也会正确传递回useAsyncData,页面就能正常获取数据了。

备注:内容来源于stack exchange,提问作者Oleksandr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 08:54:31