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

如何通过Apollo在SSR场景下实现JSON静态文件的服务端拉取

问题答复

首先直接给结论:不能直接用原生useQuery钩子以SSR模式拉取纯JSON静态文件。
useQuery的底层逻辑强绑定GraphQL协议规范,会默认校验传入的查询语句是合法GraphQL AST、返回结果匹配对应Schema结构,纯静态JSON返回的内容不满足这套校验规则,直接调用会触发解析报错,就算硬改配置绕开校验也属于工具误用,后续维护成本极高。
另外先纠正一个常见认知偏差:原生fetch并非只能在客户端执行,当前所有主流SSR运行时(Node.js 18+、Edge Runtime、各家SSR框架的服务端执行环境)都原生支持fetch API,完全可以在服务端渲染阶段直接调用fetch拉取资源,不需要等到客户端hydration阶段再执行。

可行实现方案

方案1:适配Apollo链路,复用useQuery调用习惯

如果你希望所有数据请求统一走Apollo的缓存、SSR注水逻辑,不新增额外的请求范式,可以通过自定义Apollo Link的方式把静态JSON请求整合进现有流程:

  • 给静态JSON请求加独立的上下文标记,调用useQuery时通过context字段标识这是静态资源请求,同时传入静态JSON的路径
  • 编写自定义终止链路(Terminating Link),识别到静态请求标记时,直接调用fetch拉取对应JSON文件,返回符合Apollo响应格式的结果,跳过后续GraphQL解析、Schema校验流程
  • 这种方式下静态JSON请求会和普通GraphQL请求一样,自动被Apollo的SSR收集逻辑捕获,完成服务端预取、客户端注水、缓存全流程复用,和你平时用useQuery的体验没有区别
    核心实现示例:
import { ApolloLink, Observable, InMemoryCache, ApolloClient, gql, useQuery } from '@apollo/client';

// 自定义静态JSON处理链路
const staticJsonFetchLink = new ApolloLink((operation, forward) => {
  const { fetchStaticJson, jsonPath } = operation.getContext();
  if (fetchStaticJson) {
    return new Observable(observer => {
      fetch(jsonPath)
        .then(res => {
          if (!res.ok) throw new Error(`Static JSON load failed: ${res.status}`);
          return res.json();
        })
        .then(data => {
          observer.next({ data });
          observer.complete();
        })
        .catch(err => observer.error(err));
    });
  }
  // 普通GraphQL请求走原有http链路
  return forward(operation);
});

// 初始化Client时把自定义链路放到http链路前面
const client = new ApolloClient({
  link: staticJsonFetchLink.concat(httpLink),
  cache: new InMemoryCache(),
  ssrMode: typeof window === 'undefined',
});

// 组件内调用示例
const STATIC_JSON_DUMMY_QUERY = gql`query StaticJsonPlaceholder { __typename }`;
function YourComponent() {
  const { data, loading } = useQuery(STATIC_JSON_DUMMY_QUERY, {
    context: {
      fetchStaticJson: true,
      jsonPath: '/static/your-target-file.json'
    }
  });
  // 后续使用data逻辑和普通useQuery完全一致
}

方案2:用SSR框架原生数据加载能力(生产环境优先推荐)

如果不想侵入Apollo的默认配置,直接用你所用SSR框架自带的服务端数据加载能力是最稳妥的选择,没有额外兼容成本:

  • Next.js Pages Router:在getServerSideProps(动态SSR)或getStaticProps(构建时静态生成)阶段直接用fetch拉取JSON,将结果作为props传入组件,渲染时数据已经准备完成,自动注入HTML
  • Next.js App Router:直接在服务端组件中await fetch(你的静态JSON路径)即可,框架会自动处理缓存、SSR渲染逻辑
  • Remix/Nuxt/其他SSR框架:对应使用框架提供的服务端loader(Remix)、useAsyncData(Nuxt)等官方数据加载能力,这些能力都原生支持服务端执行fetch,不需要依赖Apollo即可实现SSR阶段拉取静态JSON

避坑提示

不要在客户端组件的useEffect里拉取静态JSON,这种方式会导致SSR输出的HTML缺失对应内容,等客户端hydration完成后才会触发请求渲染,很容易出现布局偏移、SEO内容缺失的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:27:18