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

Redux Toolkit Query中如何通过PUT请求实现Token刷新重认证

fetchBaseQuery 除了接收路径字符串作为参数,还支持接收请求配置对象,自定义请求方法、请求头、请求体等所有请求参数,完全可以满足PUT方法刷新Token的需求,不需要额外引入原生fetch实现。你之前遇到的页面刷新后场景失效问题,就是因为手写原生fetch没有复用fetchBaseQuery预置的baseUrl、请求头注入、凭证携带等全局配置,导致刷新请求参数不符合接口要求。

Token存储在localStorage中不影响方案实现,只要在fetchBaseQuery的prepareHeaders钩子中统一从localStorage读取Token注入请求头即可,重试原请求时会自动带上更新后的新Token。

实现代码

直接修改原重认证包装函数即可,参考实现如下:

import { fetchBaseQuery } from '@reduxjs/toolkit/query'
import { loggedOut } from './authSlice'

// 基础请求配置,统一处理Token注入
const baseQuery = fetchBaseQuery({
  baseUrl: '/',
  // 统一从localStorage读取Token加请求头,不依赖Redux存储
  prepareHeaders: (headers) => {
    const accessToken = localStorage.getItem('accessToken')
    if (accessToken) {
      headers.set('Authorization', `Bearer ${accessToken}`)
    }
    return headers
  },
  // 如果接口需要携带Cookie,打开下面的配置
  // credentials: 'include'
})

const baseQueryWithReauth = async (args, api, extraOptions) => {
  let result = await baseQuery(args, api, extraOptions)
  
  // 命中401时尝试刷新Token
  if (result.error && result.error.status === 401) {
    // 传入对象配置发起PUT请求,和原生fetch配置规则一致
    const refreshResult = await baseQuery(
      {
        url: '/refreshToken',
        method: 'PUT',
        // 如果接口要求Refresh Token放在请求体,在这里配置,按后端要求序列化即可
        body: {
          refreshToken: localStorage.getItem('refreshToken')
        },
        // 如果Refresh Token需要放在请求头,在这里补充headers配置
        // headers: {
        //   'X-Refresh-Token': localStorage.getItem('refreshToken')
        // }
      },
      api,
      extraOptions
    )

    if (refreshResult.data) {
      // 更新localStorage中的Token
      const { accessToken, refreshToken: newRefreshToken } = refreshResult.data
      localStorage.setItem('accessToken', accessToken)
      if (newRefreshToken) {
        localStorage.setItem('refreshToken', newRefreshToken)
      }

      // 有Redux状态同步需求可以放开下面的代码
      // api.dispatch(tokenReceived(refreshResult.data))

      // 重试原始请求,此时prepareHeaders会自动读取新Token注入
      result = await baseQuery(args, api, extraOptions)
    } else {
      // 刷新失败,清除本地凭证,执行登出逻辑
      localStorage.removeItem('accessToken')
      localStorage.removeItem('refreshToken')
      api.dispatch(loggedOut())
    }
  }

  return result
}

补充说明

  • 不要在重认证逻辑中混用原生fetch:所有请求走封装好的baseQuery,才能统一复用全局配置,避免不同场景下请求参数不一致的问题,这也是你之前刷新页面场景功能异常的核心原因。
  • 如果存在页面加载时并发多个接口同时返回401的场景,可以在逻辑外层加一个刷新Promise的缓存标记,避免重复发起多次Token刷新请求,属于可选优化项,不影响基础功能使用。

内容的提问来源于stack exchange,提问作者Arcadiusz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:45:37