如何在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
相关产品推荐
相关产品推荐

