Next 13中如何让Urql GraphQL服务端组件每次请求都获取数据?
解决Next.js 13服务端组件中Urql请求不触发每次请求的问题
问题分析
你的AccountPage作为App Router下的服务端组件,默认会被Next.js静态优化缓存,导致getViewer只执行一次;同时Next.js对fetch有内置缓存机制,即使Urql设置了requestPolicy: 'network-only',也可能被Next.js的缓存拦截,无法触发每次请求的后端逻辑。
解决方案
1. 强制服务端组件动态渲染
在/app/account/page.tsx中添加动态渲染配置,禁用静态缓存:
const AccountPage = async () => { const username = await getViewer(); return <AccountView username={username} />; }; // 强制每次请求都重新渲染组件,禁用静态生成缓存 export const dynamic = 'force-dynamic';
dynamic: 'force-dynamic'会让组件在每次请求时都在服务端重新执行,而不是复用之前生成的静态结果。
2. 配置Urql适配Next.js fetch缓存规则
修改query函数,在fetchOptions中添加Next.js专属的缓存控制选项,确保请求不被Next.js缓存:
import { Client, TypedDocumentNode, createClient } from 'urql/core'; const query = async < TResponse, TVariables extends { [prop: string]: any } = Record<string, unknown> >( queryString: string | DocumentNode | TypedDocumentNode, { variables, client, cache }: { variables?: TVariables; client?: Client; cache?: RequestCache } = {} ) => await ( client ?? createClient({ url: `/api/graphql`, fetchOptions: { cache: cache ?? 'no-store', // 告诉Next.js禁用该请求的缓存,强制每次走网络 next: { revalidate: 0 } }, requestPolicy: 'network-only', fetch }) ) .query<TResponse>(queryString, variables) .toPromise();
Next.js的next.revalidate: 0会完全禁用该fetch请求的缓存,配合cache: 'no-store'双重确保请求不会被缓存。
3. 后端API禁用缓存响应头
在你的GraphQL API(/pages/api/graphql.ts)中添加响应头,防止浏览器或CDN缓存API结果:
const apolloServer = new ApolloServer({ schema, context: ({ req, res }) => { // 设置响应头禁用所有缓存 res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); return { req, res }; } });
这一步可以避免API响应被下游缓存系统拦截,确保每次请求都能触发后端的viewer resolver。
验证
完成以上配置后,每次导航到/account页面,查看后端控制台是否输出Hitting the viewer endpoint!,如果每次请求都能看到该日志,说明配置生效。
内容的提问来源于stack exchange,提问作者Anthony Bias
相关产品推荐
相关产品推荐

