useMutation Hook错误与服务器抛出的错误信息不匹配问题咨询
useMutation Hook返回错误与服务器抛出信息不匹配的问题
问题现象
- 客户端error link日志能正确输出服务器抛出的错误:
[GraphQL error]: Message: Authentication required., Location: undefined, Path: undefined - 但使用
useLazyQuery(或useMutation)时,打印返回的error得到的却是:Error: Response not successful: Received status code 400
相关代码
客户端Error Link配置
import { onError } from "@apollo/client/link/error"; const errorLink = onError(({ graphQLErrors, networkError }) => { if (graphQLErrors) graphQLErrors.forEach(({ message, locations, path }) => console.log( `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`, ), ); if (networkError) console.log(`[Network error]: ${networkError}`); }); export const client = new ApolloClient({ link: from([errorLink, authLink, uploadLink]), cache: new InMemoryCache() });
客户端查询代码
const [signIn, { loading, error, data, networkStatus }] = useLazyQuery( PROFILE, { notifyOnNetworkStatusChange: true } );
服务器端错误抛出代码
if (!user) throw new GraphQLError("Authentication required.", { extensions: { code: "UNAUTHORIZED" }, });
原因分析
这是因为服务器返回了400 HTTP状态码,Apollo Client默认会将这类非200的响应判定为网络错误,而非GraphQL业务错误。虽然error link能从响应体中解析出graphQLErrors并打印,但useQuery/useMutation返回的error会优先指向网络错误对象,而非GraphQL错误信息。
解决方法
方法1:调整服务器端返回状态码(推荐)
按照GraphQL规范,即使存在业务错误,服务器也应该返回200 HTTP状态码,将错误信息放在响应体的errors字段中。这样Apollo Client会自动识别并将GraphQL错误映射到useQuery/useMutation的error对象里,无需额外处理。
方法2:客户端自定义错误处理
如果无法修改服务器配置,可以在error link中自定义逻辑,将GraphQL错误信息注入到组件可捕获的错误中:
import { onError } from "@apollo/client/link/error"; const errorLink = onError(({ graphQLErrors, networkError, operation, forward }) => { if (graphQLErrors) { // 原打印逻辑保留 graphQLErrors.forEach(({ message, locations, path }) => console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`) ); // 处理400状态码下的GraphQL错误 if (networkError && graphQLErrors.length) { // 创建包含GraphQL错误信息的自定义错误 const customError = new Error(graphQLErrors[0].message); customError.graphQLErrors = graphQLErrors; customError.code = graphQLErrors[0].extensions?.code; // 抛出错误,让组件的error字段捕获 throw customError; } } if (networkError) console.log(`[Network error]: ${networkError}`); });
之后在组件中就可以通过error.message拿到服务器抛出的“Authentication required.”,通过error.graphQLErrors拿到完整的错误数组。
内容的提问来源于stack exchange,提问作者Raphael
相关产品推荐
相关产品推荐

