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

如何为URQL GraphQL Mutation实现全局错误处理?

全局处理Hasura Action Mutation的连接错误

问题核心

你遇到的CombinedError是urql在请求失败(如服务器宕机、网络中断)时抛出的错误,这类错误属于网络层/GraphQL服务端错误。之前mapExchange和errorExchange未触发,核心原因是你把fetchExchange放在了最前面——urql的exchange执行逻辑是请求从左到右传递,响应/错误从右到左返回,错误处理类exchange必须放在fetchExchange之前才能捕获到错误。

解决步骤

1. 调整Exchange执行顺序

将错误处理相关的errorExchange和mapExchange移到fetchExchange之前,确保错误能被正确捕获:

const createUrqlClient = (headers: StringRecord = defaultHeaders) => {
  return createClient({
    url: GRAPHQL_ENDPOINT,
    fetchOptions: {
      headers,
      credentials: 'include'
    },
    exchanges: [
      // 错误处理exchange放在最前面
      errorExchange({
        onError: (error) => {
          // 处理Hasura Action连接失败的特定错误
          if (error.graphQLErrors.length) {
            const targetError = error.graphQLErrors[0];
            if (targetError.extensions?.internal?.error?.includes('http exception when calling webhook')) {
              // 这里添加全局通知逻辑,比如弹出错误提示
              console.error('服务器连接失败,请稍后重试');
              // 示例:showGlobalNotification('服务器连接异常', 'error');
            }
          } 
          // 处理纯网络错误(如断网、DNS解析失败)
          else if (error.networkError) {
            console.error('网络连接异常,请检查网络状态');
          }
        },
      }),
      mapExchange({
        onResult: (result) => {
          // 可选:在这里补充处理结果或额外错误检查
          if (result.error) {
            console.debug('请求结果返回错误:', result.error);
          }
        },
      }),
      cacheExchange,
      fetchExchange,
      subscriptionExchange({
        forwardSubscription(request) {
          const input = { ...request, query: request.query || '' };
          return {
            subscribe(sink) {
              const unsubscribe = getWsClient(headers).subscribe(input, sink);
              return { unsubscribe };
            }
          };
        }
      })
    ]
  });
};

2. 修正Mutation Hook的错误捕获逻辑

你的useAuthentication Hook未处理signOutMutation抛出的错误,需要补充try/catch确保错误能被全局exchange捕获,同时避免未捕获Promise错误:

import { useMutation } from 'urql';

export const useAuthentication = () => {
  const [, signOutMutation] = useMutation(SignOutAction);
  const signOut = async () => {
    try {
      const { data, error } = await signOutMutation({ email: appState.user.email });
      if (error) return false;
      if (data?.signOut.isSuccess) clearAuthState();
      return data?.signOut.isSuccess;
    } catch (err) {
      // 捕获极端情况下未被urql处理的错误
      console.error('登出操作失败:', err);
      return false;
    }
  };

  return { signOut };
};

3. 区分错误类型精准处理

urql的CombinedError包含两类错误,可针对性处理:

  • graphQLErrors: GraphQL服务端返回的错误(如Hasura Action调用webhook失败)
  • networkError: 纯网络层错误(如断网、服务器无法访问)

关键注意事项

  • Exchange顺序是核心:错误处理类exchange必须在fetchExchange之前,否则无法捕获请求阶段的错误
  • Hasura Action的错误会被包装在graphQLErrors[0].extensions.internal.error中,可通过字段内容匹配特定错误场景
  • 全局处理后,无需在每个Mutation Hook中重复编写错误处理逻辑,大幅减少代码冗余

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:11:26