RTK Query结合GraphQL与Header Access Token时遇状态序列化错误
问题解决:RTK Query + GraphQL 携带Token请求失败及非序列化错误
问题核心
- Postman中可用的Access Token,在RTK Query环境下无法正确携带,请求失败
- 每次查询抛出
Non-serializable value was detected in the state.错误 - 需要实现正常的GraphQL数据获取、错误状态及加载状态管理
错误原因分析
- graphql-request调用错误:
request函数的第三个参数是查询变量,而非请求头,导致Token未正确携带到请求中 - 不可序列化错误对象:错误处理时直接返回
ClientError实例,Redux状态要求所有值必须可序列化,Error实例不符合要求 - transformResponse处理冗余:错误逻辑应在baseQuery中处理,而非在transformResponse中重复处理
解决方案
1. 修正graphql-request的请求头传递方式
将请求头作为request函数的第四个参数(或放入options对象),确保Token被正确携带
2. 错误处理返回可序列化数据
捕获错误时,仅提取status、message、response data等可序列化属性,避免直接返回Error实例
3. 简化transformResponse逻辑
移除冗余的错误处理,让RTK Query自动管理数据、错误及加载状态
修改后的完整代码
import { createApi } from "@reduxjs/toolkit/query/react"; import { request, gql, ClientError } from "graphql-request"; const API_ENDPOINT = "https://c97663-2.myshopify.com/api/2023-01/graphql.json"; // 符合RTK Query规范的GraphQL基础查询函数 const graphqlBaseQuery = ({ baseUrl, headers }: { baseUrl: string; headers: HeadersInit }) => async ({ body }: { body: string }) => { try { // 正确传递请求头:作为request函数的第四个参数 const result = await request(baseUrl, body, {}, headers); return { data: result }; } catch (error) { if (error instanceof ClientError) { const { status, data } = error.response; // 返回可序列化的错误对象,不含Error实例 return { error: { status, message: error.message, data: data || { message: status === 403 && data?.extensions?.code === "ACCESS_DENIED" ? "Access denied" : "GraphQL request failed" } } }; } // 处理非ClientError类型的错误 return { error: { status: 500, message: (error as Error).message || "Unknown server error", data: {} } }; } }; export const productsApi = createApi({ baseQuery: graphqlBaseQuery({ baseUrl: API_ENDPOINT, headers: { "X-Shopify-Storefront-Access-Token": "07a059546dee3d048794dc7744f6183a", "Content-Type": "application/json", }, }), endpoints: (builder) => ({ getProducts: builder.query({ query: () => ({ body: gql` query { products(first: 10) { edges { node { id title description productType tags availableForSale createdAt variants(first: 1) { edges { node { id sku title priceV2 { amount currencyCode } image { originalSrc } } } } } } } } `, }), // 移除冗余的transformResponse,RTK Query会自动处理数据返回 }), }), }); export const { useGetProductsQuery } = productsApi;
使用方式
在组件中直接使用生成的Hook,获取数据、错误及加载状态:
import { useGetProductsQuery } from './path/to/productsApi'; const ProductList = () => { const { data, error, isLoading } = useGetProductsQuery(); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error: {(error as any).message}</div>; return ( <div> {data?.products?.edges.map((edge: any) => ( <div key={edge.node.id}> <h3>{edge.node.title}</h3> <p>{edge.node.description}</p> </div> ))} </div> ); };
内容的提问来源于stack exchange,提问作者benyx
相关产品推荐
相关产品推荐

