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

如何在Apollo Client中重试失败的Next.js SSR预览查询?

Next.js SSR预览请求Apollo Client失败重试官方实现方案

问题场景

Next.js服务端渲染(SSR)中,预览请求对应的GraphQL查询偶尔会因为后端未就绪导致首次调用失败。轮询方案不符合“仅出错时重试”的需求,目前已通过自定义函数实现重试,但希望使用Apollo官方方案替代。

现有代码(原请求逻辑)

const PREVIEW = {
  query: MY_PREVIEW_QUERY,
  variables: { id, since },
  fetchPolicy: "no-cache",
  notifyOnNetworkStatusChange: true,
  context: {
    headers: {
      cookie,
    },
  },
};
const { data, errors } = await apiApolloFetch(
  isPreviewRequest ? PREVIEW : STANDARD
);

if (errors) console.warn(errors);

当前自定义重试实现

const fetchPreview = async () => {
  let resp = await apiApolloFetch(PREVIEW);
  if (resp.data.preview == null) {
    await delay(2000);
    resp = await apiApolloFetch(PREVIEW);
  }
  return resp;
};

const { data, errors } = isPreviewRequest
  ? await fetchPreview()
  : await apiApolloFetch(STANDARD);

Apollo官方RetryLink解决方案

1. 安装依赖(若未安装)

确保已安装核心Apollo客户端包:

npm install @apollo/client

2. 配置RetryLink与自定义链路

根据失败场景分两种情况处理:

情况A:后端返回HTTP/网络错误(如503)

直接通过RetryLink针对标记为预览的请求做重试:

import { ApolloClient, InMemoryCache, from } from '@apollo/client';
import { RetryLink } from '@apollo/client/link/retry';
import { createHttpLink } from '@apollo/client/link/http';

// 基础HTTP链路
const httpLink = createHttpLink({
  uri: '/api/graphql', // 替换为你的GraphQL接口地址
});

// 配置重试链路:仅对预览请求重试1次,延迟2秒
const retryLink = new RetryLink({
  delay: {
    initial: 2000, // 首次重试延迟
    max: 2000, // 最大延迟
    jitter: false // 固定延迟,不添加随机抖动
  },
  attempts: {
    max: 1, // 重试次数,和自定义逻辑一致
  },
  retryIf: (error, operation) => {
    // 仅对标记为preview的请求且存在错误时重试
    return operation.getContext().preview && !!error;
  },
});

// 创建Apollo Client,组合链路
const client = new ApolloClient({
  link: from([retryLink, httpLink]),
  cache: new InMemoryCache(),
});

情况B:请求成功但返回数据为空(data.preview为null)

添加自定义链路,将数据为空的情况转为错误,触发RetryLink重试:

import { ApolloLink } from '@apollo/client';

// 自定义链路:检查预览请求的返回数据,为空则抛出错误
const previewDataCheckLink = new ApolloLink((operation, forward) => {
  return forward(operation).map((response) => {
    const isPreview = operation.getContext().preview;
    if (isPreview && response.data?.preview == null) {
      // 抛出错误,让RetryLink捕获并重试
      throw new Error('Preview content not ready');
    }
    return response;
  });
});

// 更新链路组合顺序:数据检查 → 重试 → HTTP请求
const client = new ApolloClient({
  link: from([previewDataCheckLink, retryLink, httpLink]),
  cache: new InMemoryCache(),
});

3. 标记预览请求

在预览请求的context中添加preview: true,让链路识别:

const PREVIEW = {
  query: MY_PREVIEW_QUERY,
  variables: { id, since },
  fetchPolicy: "no-cache",
  notifyOnNetworkStatusChange: true,
  context: {
    headers: { cookie },
    preview: true, // 标记为预览请求
  },
};

4. 发起请求

保持原请求逻辑即可,链路会自动处理重试:

const { data, errors } = await apiApolloFetch(
  isPreviewRequest ? PREVIEW : STANDARD
);

if (errors) console.warn(errors);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:40:48