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

Apollo Client中RetryLink无法读取响应headers的问题咨询

问题原因
  • Apollo Link 执行顺序是请求从数组第一个链路向后传递到最末端的HTTP链路,响应/错误从末端向前冒泡返回。你当前链路里RetryLink放在最前面,httpLink在最后,429这类错误响应是从httpLink直接沿错误通道向上抛出的。
  • 普通200响应会被httpLink自动挂载到operation的context上,所以你写的afterware在map回调里能读到headers;但错误响应不会自动写入context,等错误传到RetryLink触发delay/attempts回调时,context里自然没有带headers的response对象。
  • 官方RetryLink本身不会主动从抛出的错误对象里提取response信息写入context,所以直接读context拿不到值。
  • 另外你当前响应是cors类型,如果服务端没把需要读取的头加到Access-Control-Expose-Headers里,哪怕拿到response对象,浏览器也会拦截头读取,表现为Headers对象为空。
解决步骤
  1. 新增一个中间链路,放在RetryLink和authLink/httpLink之间,不管是正常响应还是错误响应,都提前把response对象写入operation的context,再把结果/错误继续向上传递:
const injectResponseContextLink = new ApolloLink((operation, forward) => {
  return forward(operation)
    .map(response => {
      // 正常响应写入context
      operation.setContext(prev => ({ ...prev, response: response.response }));
      return response;
    })
    .catch(err => {
      // 错误响应也写入context
      if (err.response) {
        operation.setContext(prev => ({ ...prev, response: err.response }));
      }
      throw err;
    });
});
  1. 调整Apollo Client的链路顺序,确保响应/错误先经过上面的注入链路,再到达RetryLink:
const createApolloClient = () => {
  return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    // 链路顺序从前往后:重试逻辑 -> 响应注入 -> 鉴权 -> HTTP请求
    link: from([retryLink, injectResponseContextLink, authLink.concat(httpLink)]),
    cache: new InMemoryCache()
  });
};
  1. 调整RetryLink的逻辑,优先读取服务端返回的Retry-After头,兜底走原有随机退避逻辑即可:
const retryLink = new RetryLink({
  attempts: (count, _, error) => {
    // 建议只对429限流错误做重试,其他错误直接抛出
    return count <= 5 && !!error && error.statusCode === 429;
  },
  delay: (count, operation) => {
    const { response } = operation.getContext();
    if (response?.headers) {
      const retryAfter = response.headers.get('Retry-After');
      // Retry-After如果返回的是秒数直接转毫秒,是日期格式的话可以自己加转换逻辑
      if (retryAfter && !isNaN(Number(retryAfter))) {
        return Number(retryAfter) * 1000;
      }
    }
    return count * 1000 * Math.random();
  }
});
额外校验项

跨域场景下让后端把Retry-After以及你需要读取的其他自定义响应头,加入CORS配置的Access-Control-Expose-Headers列表,否则浏览器会出于安全限制禁止JS读取这些头,哪怕请求实际返回了头你也拿不到。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:25:25