Next.js中Apollo Client拒绝更新缓存,求彻底禁用缓存方案
在Next.js 14.2.5 SSR环境中彻底禁用Apollo Client缓存,强制每次获取最新数据
我们在Next.js 14.2.5的SSR环境中使用Apollo Client,通过getClient初始化客户端,但无论怎么配置,Apollo Client都不会用服务器返回的最新数据更新缓存。已经用Postman验证API返回的是最新数据,但查询始终返回旧数据。尝试过设置fetch-policy为no-cache、修改defaultOptions禁用缓存、切换客户端、禁用Next.js缓存,都没效果。需求是每次页面加载都从API获取最新数据,彻底禁用任何缓存机制。
现有相关代码
Apollo客户端配置
import { HttpLink } from "@apollo/client"; import { registerApolloClient, ApolloClient, InMemoryCache, } from "@apollo/experimental-nextjs-app-support"; export const { getClient } = registerApolloClient(() => { return new ApolloClient({ link: new HttpLink({ uri: `${process.env.NEXT_PUBLIC_ADMIN_BASE_URI}/api/graphql`, }), defaultOptions: { query: { fetchPolicy: "network-only", }, }, ssrMode: true, ssrForceFetchDelay: 1, cache: new InMemoryCache({ resultCaching: false, typePolicies: { Yachts: { merge: true, fields: { keyFeatures: { merge(existing = [], incoming: any[], { readField }) { const merged: any[] = existing ? existing.slice(0) : []; const featureNameToIndex: Record<string, number> = {}; existing.forEach((feature: any, index: any) => { const name = readField<string>("name", feature); if (name) { featureNameToIndex[name] = index; } }); incoming.forEach((feature) => { const name = readField<string>("name", feature); if (name) { const index = featureNameToIndex[name]; if (typeof index === "number") { merged[index] = { ...merged[index], ...feature, }; } else { featureNameToIndex[name] = merged.length; merged.push(feature); } } }); return merged; }, }, }, }, }, }), /*defaultOptions: { watchQuery: { fetchPolicy: "no-cache", errorPolicy: "ignore", }, query: { fetchPolicy: "no-cache", errorPolicy: "all", }, mutate: { fetchPolicy: "no-cache", }, },*/ }); });
服务端查询函数
"use server"; import IBrokerino from "@/types/brokerino"; import { getClient } from "@/apollo"; import { gql } from "@apollo/client"; export const fetchBrokerinos = async (): Promise<IBrokerino[]> => { const client = getClient(); const { data } = await client.query({ query: gql` query Users { Users(where: { displayOnWebsite: { equals: true } }) { docs { name picture { alt sizes { fhd { url width height } } } phones { prefix number } langs email position } } } `, }); return data.Users.docs; };
Page组件调用方式
import Hero from "@/components/company/hero"; import Bar from "@/components/nav/bar"; import dynamic from "next/dynamic"; import { fetchBrokerinos } from "@/actions/brokerino"; const View = dynamic(() => import("@/components/view")); const Footer = dynamic(() => import("@/components/footer")); const Story = dynamic(() => import("@/components/company/story")); const Accordion = dynamic(() => import("@/components/company/accordion")); const Team = dynamic(() => import("@/components/company/team")); const Lifestyle = dynamic(() => import("@/components/company/lifestyle")); const Company = async () => { return ( <main className="w-full flex flex-col justify-start items-center"> <Bar dynamicColor={-1} /> <View /> <Hero /> <Story /> <Accordion /> <Team brokerinos={await fetchBrokerinos()} /> <Lifestyle /> <Footer /> </main> ); }; export default Company;
彻底禁用缓存的解决方案
1. 单个查询强制禁用缓存
在查询函数中明确指定fetchPolicy和nextFetchPolicy,确保该查询完全绕过缓存:
export const fetchBrokerinos = async (): Promise<IBrokerino[]> => { const client = getClient(); const { data } = await client.query({ query: gql`...`, // 保留原查询语句 fetchPolicy: "no-cache", // 不从缓存读取,也不写入缓存 nextFetchPolicy: "no-cache", // 后续重复查询也遵循该策略 }); return data.Users.docs; };
2. 全局配置Apollo客户端禁用缓存
修改客户端初始化代码,关闭所有缓存相关机制:
export const { getClient } = registerApolloClient(() => { return new ApolloClient({ link: new HttpLink({ uri: `${process.env.NEXT_PUBLIC_ADMIN_BASE_URI}/api/graphql`, // 禁用HTTP层面的缓存 fetchOptions: { cache: "no-store", }, }), defaultOptions: { watchQuery: { fetchPolicy: "no-cache", errorPolicy: "all", }, query: { fetchPolicy: "no-cache", errorPolicy: "all", nextFetchPolicy: "no-cache", }, mutate: { fetchPolicy: "no-cache", }, }, ssrMode: true, // 清空缓存规则,关闭结果缓存 cache: new InMemoryCache({ resultCaching: false, typePolicies: {}, }), }); });
极端情况:可以直接导入
NoCache替代InMemoryCache,彻底移除缓存层。
3. 禁用Next.js服务端组件缓存
在Page组件顶部添加revalidate: 0,强制Next.js每次请求都重新渲染页面:
export const revalidate = 0; // 每次请求都重新生成页面 const Company = async () => { // 保留原组件代码 }; export default Company;
或者在服务端查询函数中使用noStore禁用函数级缓存:
"use server"; import { unstable_noStore as noStore } from "next/cache"; // 其他导入语句 export const fetchBrokerinos = async (): Promise<IBrokerino[]> => { noStore(); // 禁用该函数的缓存 const client = getClient(); const { data } = await client.query({ query: gql`...`, fetchPolicy: "no-cache", }); return data.Users.docs; };
4. 验证请求是否触发
在HttpLink中添加日志,确认每次页面加载都发起了新请求:
link: new HttpLink({ uri: `${process.env.NEXT_PUBLIC_ADMIN_BASE_URI}/api/graphql`, fetchOptions: { cache: "no-store" }, fetch: async (uri, options) => { console.log("发起GraphQL请求:", uri); return fetch(uri, options); }, }),
内容的提问来源于stack exchange,提问作者Gregory Buffard
相关产品推荐
相关产品推荐

