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

@apollo/client useLazyQuery遇错误仍触发.then(),useMutation正常触发.catch()

问题原因及解决方案

这是Apollo Client(你使用的useLazyQuery/useMutation属于Apollo生态)对GraphQL查询和变更的错误处理逻辑差异导致的,核心原因在于GraphQL的响应特性和Apollo的设计倾向:

1. GraphQL响应的本质

不管是查询(Query)还是变更(Mutation),只要HTTP请求本身成功(状态码200),即使存在业务/权限错误,后端都会返回包含data(可能为null)和errors字段的JSON响应,而非HTTP错误状态码。

2. Apollo Client的处理差异

  • useLazyQuery/useQuery:默认将GraphQL层面的错误(比如你遇到的权限不足)视为“可容忍”的情况——因为查询可能允许部分字段成功返回,所以Promise会正常resolve,错误被放在返回结果的errors数组里,不会触发.catch()。只有当出现网络错误(比如HTTP 500、请求超时、跨域失败)时,才会触发.catch()。
  • useMutation:默认将GraphQL错误视为“严重错误”——因为变更操作通常是原子性的(要么全成要么全败),所以当响应里存在errors时,Apollo会主动将这些错误抛出,触发Promise的.catch()。

3. 解决方法

方法一:手动检查useLazyQuery的返回结果

在.then()回调里主动判断errors字段,处理业务错误:

const [getMe] = useLazyQuery(ME_QUERY);

getMe()
  .then(result => {
    if (result.errors) {
      // 处理权限错误等业务逻辑错误
      alert(result.errors[0].message);
      return;
    }
    // 处理正常返回的数据
    console.log(result.data.me);
  })
  .catch(networkError => {
    // 处理网络层面的错误
    console.error('网络请求失败:', networkError);
  });

方法二:修改errorPolicy强制抛出错误

给useLazyQuery设置errorPolicy: 'none',让Apollo把GraphQL错误当作Promise reject的触发条件,这样就能在.catch()里统一处理所有错误:

const [getMe] = useLazyQuery(ME_QUERY, {
  errorPolicy: 'none'
});

getMe()
  .then(result => {
    // 只有完全无错误时才会走到这里
    console.log(result.data.me);
  })
  .catch(error => {
    // 这里会捕获GraphQL错误和网络错误
    console.error(error.message);
  });

方法三:手动抛出错误触发catch

在.then()里检测到errors时,主动抛出错误,让后续的.catch()处理:

getMe()
  .then(result => {
    if (result.errors) {
      throw new Error(result.errors[0].message);
    }
    return result.data;
  })
  .then(data => {
    console.log(data.me);
  })
  .catch(error => {
    console.error('错误:', error.message);
  });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:16:08