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

如何在RTK Query中实现Refresh Token刷新功能?

在RTK Query中实现Token自动刷新的正确方式

核心问题分析

你遇到的报错是因为React Hook只能在组件或自定义Hook中调用,不能在普通工具函数里使用useLazyGetRefreshTokensQuery。正确的做法是利用RTK Query的自定义baseQuery逻辑,通过非Hook方式触发token刷新请求,统一处理所有API的token验证与刷新。


方案一:捕获401错误后自动刷新并重试请求

这种方式无需提前判断token过期,等后端返回401(token失效)时再触发刷新,实现简单。

1. 定义刷新Token的API端点

先创建用于刷新token的独立API(如果还没实现):

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

export const authApi = createApi({
  reducerPath: 'authApi',
  baseQuery: fetchBaseQuery({ baseUrl: '/api/auth' }),
  endpoints: builder => ({
    refreshToken: builder.mutation({
      query: refreshToken => ({
        url: '/refresh',
        method: 'POST',
        body: { refreshToken }
      })
    })
  })
});

// 组件中可以用这个Hook,但我们在baseQuery里用非Hook方式调用
export const { useRefreshTokenMutation } = authApi;

2. 封装带刷新逻辑的自定义baseQuery

扩展fetchBaseQuery,加入401错误拦截与token刷新逻辑:

import { fetchBaseQuery, BaseQueryFn } from '@reduxjs/toolkit/query/react';
import { RootState } from '../store'; // 导入你的Redux Store根类型
import { authApi } from './authApi';
// 假设你有这些工具函数:获取/存储token、刷新token
import { getAccessToken, getRefreshToken, setAccessToken, clearAuthData } from '../util/userContextManagement';

// 基础查询逻辑
const baseQuery = fetchBaseQuery({
  baseUrl: '/api/users/current',
  prepareHeaders: (headers) => {
    const token = getAccessToken()?.token;
    if (token) {
      headers.set('Authorization', `Bearer ${token}`);
    }
    return headers;
  }
});

// 带token刷新的增强版baseQuery
const baseQueryWithReauth: BaseQueryFn = async (args, api, extraOptions) => {
  let result = await baseQuery(args, api, extraOptions);

  // 检测是否为token过期导致的401错误
  if (result.error && result.error.status === 401) {
    const refreshToken = getRefreshToken();
    if (refreshToken) {
      // 用dispatch触发刷新请求(非Hook方式,避免报错)
      const refreshResult = await api.dispatch(
        authApi.endpoints.refreshToken.initiate(refreshToken)
      );

      if (refreshResult.data) {
        // 保存新的access token
        setAccessToken(refreshResult.data);
        // 重试原请求
        result = await baseQuery(args, api, extraOptions);
      } else {
        // 刷新失败,清除本地授权数据并跳转登录页
        clearAuthData();
        window.location.href = '/login';
      }
    } else {
      // 无刷新token,直接跳转登录
      clearAuthData();
      window.location.href = '/login';
    }
  }

  return result;
};

3. 在业务API中使用增强版baseQuery

修改你的contactsApi,替换原有的baseQuery:

import { createApi } from '@reduxjs/toolkit/query/react';
import { Contacts } from '../datamodel/Contact';
import { baseQueryWithReauth } from './baseQueryWithReauth';

export const contactsApi = createApi({
  reducerPath: 'contactsApi',
  baseQuery: baseQueryWithReauth, // 使用带刷新逻辑的baseQuery
  endpoints: builder => ({
    getContacts: builder.query<Contacts, void>({
      query: () => '/contacts' // GET请求可简化写法
    })
  })
});

export const { useGetContactsQuery } = contactsApi;

方案二:提前检测Token过期,主动刷新

如果你的token包含过期时间,可以在请求发起前主动检查并刷新,避免401错误,体验更流畅。

修改prepareHeaders为异步函数,提前处理token刷新:

const baseQuery = fetchBaseQuery({
  baseUrl: '/api/users/current',
  prepareHeaders: async (headers, { api }) => {
    let tokenData = getAccessToken();
    let token = tokenData?.token;
    const expiresAt = tokenData?.expiresAt;

    // 提前1分钟刷新即将过期的token
    if (token && expiresAt && Date.now() >= expiresAt - 60000) {
      const refreshToken = getRefreshToken();
      if (refreshToken) {
        const refreshResult = await api.dispatch(
          authApi.endpoints.refreshToken.initiate(refreshToken)
        );
        
        if (refreshResult.data) {
          token = refreshResult.data.accessToken;
          setAccessToken(refreshResult.data);
        } else {
          clearAuthData();
          token = null;
        }
      }
    }

    if (token) {
      headers.set('Authorization', `Bearer ${token}`);
    }
    return headers;
  }
});

关键注意事项

  • 不要在非Hook函数中调用RTK Query的Hook,改用api.dispatch(api.endpoints.xxx.initiate(...))触发请求,这是官方支持的非Hook调用方式。
  • 刷新token后必须更新本地存储的token,确保后续请求使用新token。
  • 刷新失败时要及时清除本地授权数据并跳转登录页,避免无限循环请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:40:20