如何在Redux Toolkit RTK Query GraphQL应用中包装graphqlRequestBaseQuery处理过期令牌
包装graphqlRequestBaseQuery实现令牌自动刷新(TypeScript示例)
以下是基于你现有代码的完整实现,包含TypeScript类型定义和令牌刷新逻辑:
import { createApi, BaseQueryFn } from "@reduxjs/toolkit/query/react"; import { graphqlRequestBaseQuery } from "@rtk-query/graphql-request-base-query"; import { ClientError, GraphQLClient } from "graphql-request"; import { RootState } from "../store"; // 导入你的auth slice action(需自行定义) import { authActions } from "../features/auth/authSlice"; const baseUrl = process.env.REACT_APP_TECHNOTES_API_HTTP_GRAPHQL; const techNotesHttpAPI = baseUrl ? baseUrl : "http://localhost:4001/graphql"; // 定义刷新令牌相关类型 interface RefreshTokenResponse { refreshToken: { accessToken: string; refreshToken: string; }; } // 原基础查询 const baseQuery = graphqlRequestBaseQuery< Partial<ClientError> & { statusCode: number; error: string } >({ url: techNotesHttpAPI, prepareHeaders: (headers, { getState }) => { const state = getState() as RootState; const token = state.auth.token; if (token) { headers.set("Authorization", `Bearer ${token}`); } return headers; }, customErrors: ({ name, stack, response }) => { const { message = "", statusCode = 500, error = "", } = response?.errors?.length ? response?.errors[0]?.extensions.response : {}; return { name, message, statusCode, error, stack, }; }, }); // 带令牌刷新的包装查询 const baseQueryWithReauth: BaseQueryFn< Parameters<typeof baseQuery>[0], unknown, Partial<ClientError> & { statusCode: number; error: string } > = async (args, api, extraOptions) => { let result = await baseQuery(args, api, extraOptions); // 捕获访问令牌过期的401错误 if (result.error?.statusCode === 401) { const state = api.getState() as RootState; const refreshToken = state.auth.refreshToken; if (refreshToken) { try { // 发送刷新令牌请求(根据你的API调整mutation内容) const client = new GraphQLClient(techNotesHttpAPI); const refreshResult = await client.request<RefreshTokenResponse>( `mutation RefreshToken($refreshToken: String!) { refreshToken(refreshToken: $refreshToken) { accessToken refreshToken } }`, { refreshToken } ); // 更新redux中的令牌状态 api.dispatch( authActions.setCredentials({ token: refreshResult.refreshToken.accessToken, refreshToken: refreshResult.refreshToken.refreshToken, }) ); // 重试原请求 result = await baseQuery(args, api, extraOptions); } catch (refreshError) { // 刷新令牌失效,清除登录状态 api.dispatch(authActions.logout()); } } else { // 无刷新令牌,直接清除登录状态 api.dispatch(authActions.logout()); } } return result; }; export const apiSlice = createApi({ reducerPath: "api", baseQuery: baseQueryWithReauth, // 使用包装后的查询 tagTypes: ["User", "Note"], endpoints: () => ({}), });
关键说明
- 类型匹配:
BaseQueryFn的泛型参数严格对应原baseQuery的参数、返回数据、错误类型,确保TypeScript类型校验通过。 - 错误识别:通过
statusCode: 401判断访问令牌过期,可根据你的API错误格式调整判断逻辑。 - 刷新逻辑:使用
graphql-request直接发送刷新mutation(如果你的刷新接口是REST,可替换为fetch或fetchBaseQuery)。 - 状态同步:获取新令牌后,通过redux action更新全局auth状态,保证后续请求自动使用新令牌。
- 降级处理:刷新令牌失效时,清除登录状态,引导用户重新登录。
内容的提问来源于stack exchange,提问作者Dwight
相关产品推荐
相关产品推荐

