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

Apollo错误处理:如何区分503与其他5xx错误

问题

我有一个使用Apollo从GraphQL端点获取数据的React应用。我已设置error link方法,当GQL返回HTTP错误时展示不同消息,这在处理4xx错误时正常工作。但当服务器返回5xx错误时,我在方法中仅得到通用的“failed to fetch”错误消息,无法获取错误码。

503错误通常表示系统处于维护模式,因此我希望能区分503和其他5xx错误以展示不同消息。是否可以调整错误处理逻辑来获取5xx错误的状态码?我在传入方法的errorResponse中未发现明显相关内容。

以下是我的onError link简化版本:

const errorLink = onError((errorResponse) => {
  const { graphQLErrors, networkError, operation } = errorResponse;

  // Doesn't work - networkError is null.
  if ((
    networkError?.statusCode === 503
  ) && !window.location.pathname.includes('maintenance-mode')
  ) {
    // [show maintenance mode page]
  }

  // This works.
  if (networkError?.statusCode === 401 && operation?.operationName !== 'auth') {
    // [redirect to login page]
  }

  // [...etc]
});
解决方案

问题出在Apollo Client默认的fetch实现对5xx错误的处理上——当服务器返回5xx状态码时,它会抛出通用的TypeError: failed to fetch,不会将错误包装成带状态码的networkError对象。你可以通过以下两种方式解决:

1. 自定义fetch策略(推荐)

替换Apollo Client使用的fetch方法,手动处理HTTP错误,将状态码附加到错误对象中:

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { onError } from '@apollo/client/link/error';

// 自定义fetch函数
const customFetch = async (uri, options) => {
  const response = await fetch(uri, options);
  // 非2xx响应时手动抛出带状态码的错误
  if (!response.ok) {
    const error = new Error(response.statusText);
    error.statusCode = response.status;
    throw error;
  }
  return response;
};

// 创建HTTP link时使用自定义fetch
const httpLink = createHttpLink({
  uri: '你的GraphQL端点地址',
  fetch: customFetch,
});

// 错误处理link保持原有逻辑,此时networkError会包含statusCode
const errorLink = onError((errorResponse) => {
  const { networkError, operation } = errorResponse;

  if (networkError?.statusCode === 503 && !window.location.pathname.includes('maintenance-mode')) {
    // 展示维护页面的逻辑
  }

  if (networkError?.statusCode === 401 && operation?.operationName !== 'auth') {
    // 跳转到登录页的逻辑
  }
});

// 组合links并创建Client实例
const client = new ApolloClient({
  link: errorLink.concat(httpLink),
  cache: new InMemoryCache(),
});

2. 解析networkError的底层错误对象

如果不想替换整个fetch,可尝试从networkError的cause属性中获取原始响应(兼容性取决于运行环境):

const errorLink = onError((errorResponse) => {
  const { networkError, operation } = errorResponse;
  
  let statusCode;
  // 尝试从错误的cause属性中解析状态码
  if (networkError?.cause instanceof Response) {
    statusCode = networkError.cause.status;
  } else if (networkError?.statusCode) {
    statusCode = networkError.statusCode;
  }

  if (statusCode === 503 && !window.location.pathname.includes('maintenance-mode')) {
    // 展示维护页面
  }

  if (statusCode === 401 && operation?.operationName !== 'auth') {
    // 跳转登录页
  }
});

注意:第二种方法的兼容性有限,部分旧浏览器可能不支持cause属性,因此第一种自定义fetch的方式更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 21:55:10