Next.js App Router中Apollo GraphQL的Webhook触发按需重验证实现
在Next.js App Router + Apollo GraphQL中实现按需重验证(Webhook触发)
核心思路
Apollo本身没有内置对应Next.js按需重验证的配置,但可以通过给Apollo查询关联Next.js缓存标签,再结合Next.js的revalidateTag/revalidatePathAPI,通过Webhook触发精准重验证。
步骤1:给Apollo查询绑定Next.js缓存标签
在使用Apollo的useSuspenseQuery(或其他SSR兼容的查询Hook)时,通过context.next.tags给查询关联Next.js缓存标签,后续即可通过该标签触发重验证:
import { useSuspenseQuery } from '@apollo/experimental-nextjs-app-support/ssr'; import { GET_POSTS } from '../graphql/queries'; export default function PostsPage() { const { data } = useSuspenseQuery(GET_POSTS, { context: { // 绑定Next.js缓存标签,后续通过此标签触发重验证 next: { tags: ['posts'], }, }, }); return ( <div> {data.posts.map(post => ( <div key={post.id}>{post.title}</div> ))} </div> ); }
步骤2:创建Webhook触发重验证的API路由
在app/api/revalidate/route.ts中创建POST路由,调用Next.js的revalidateTagAPI触发指定标签的重验证(按需换成revalidatePath可重验证整个路径):
import { revalidateTag } from 'next/cache'; import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { // 建议添加Webhook鉴权逻辑(比如验证请求签名),防止恶意调用 const { tag } = await request.json(); if (!tag) { return NextResponse.json({ message: '缺少必填参数tag' }, { status: 400 }); } try { await revalidateTag(tag); return NextResponse.json({ revalidated: true, timestamp: Date.now() }); } catch (error) { return NextResponse.json({ message: '重验证失败' }, { status: 500 }); } }
步骤3:确保Apollo客户端配置兼容Next.js缓存
使用NextSSRApolloClient并配置正确的缓存集成,让Apollo查询的缓存逻辑由Next.js接管:
// app/lib/apollo-client.ts import { NextSSRApolloClient } from '@apollo/experimental-nextjs-app-support/ssr'; import { InMemoryCache } from '@apollo/client'; export function makeApolloClient() { return new NextSSRApolloClient({ cache: new InMemoryCache(), uri: process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT, next: { // 禁用Apollo自身重验证逻辑,完全交给Next.js处理 revalidate: false, }, }); }
可选:客户端侧同步清除Apollo缓存
如果需要在客户端触发重验证后同步清除Apollo的内存缓存,可在客户端组件中调用Apollo客户端的缓存操作:
'use client'; import { useApolloClient } from '@apollo/client'; import { useRouter } from 'next/navigation'; export default function RevalidateButton() { const client = useApolloClient(); const router = useRouter(); const triggerRevalidate = async () => { // 调用Webhook路由 await fetch('/api/revalidate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tag: 'posts' }), }); // 清除Apollo对应标签的缓存 client.cache.evict({ tag: 'posts' }); // 刷新页面获取最新数据 router.refresh(); }; return <button onClick={triggerRevalidate}>刷新文章列表</button>; }
内容的提问来源于stack exchange,提问作者vipul
相关产品推荐
相关产品推荐

