Next 13路由切换与getServerSideProps缓存问题求助
问题描述
在基于T3栈(Next-13、Trpc、Prisma、Next-Auth)的Next.js项目部署到Vercel后,出现路由缓存异常:使用router.push、replace或Link组件切换路由时,页面加载的是缓存的旧数据而非最新数据。
具体表现:
- 4个路由均通过
getServerSideProps加载用户信息和布局偏好初始数据 - 本地开发环境下,路由切换与
getServerSideProps配合正常 - 部署到Vercel后,修改用户信息并同步到数据库,切换路由时
page.tsx和_app.tsx仍获取旧缓存数据(尽管getServerSideProps已拉取到最新数据) - 仅首次加载页面或手动刷新时,能正常获取最新数据
项目配置(next.config.js)
/** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. * This is especially useful for Docker builds. */ import withPWA from "next-pwa"; !process.env.SKIP_ENV_VALIDATION && (await import("./src/env.mjs")); /** @type {import("next").NextConfig} */ const config = { reactStrictMode: true, headers: async () => [ { source: "/myapp/:route", headers: [ { key: "Cache-Control", value: "no-store", }, { key: "x-middleware-cache", value: "no-cache", }, ], }, ], webpack(config) { config.module.rules.push({ test: /\.svg$/i, issuer: /\.[jt]sx?$/, use: ["@svgr/webpack"], }); return config; }, /** * If you have the "experimental: { appDir: true }" setting enabled, then you * must comment the below `i18n` config out. * * @see https://github.com/vercel/next.js/issues/41980 */ i18n: { locales: ["en"], defaultLocale: "en", }, }; export default withPWA({ dest: "public", disable: process.env.NODE_ENV === "development", })(config);
getServerSideProps示例
export const getServerSideProps = withSession<{ props: { data: UserDataState; }; }>(async (session, ctx) => { ctx.res.setHeader("Cache-Control", "no-cache"); ctx.res.setHeader("x-middleware-cache", "no-cache"); const helpers = createServerSideHelpers({ router: appRouter, ctx: createInnerTRPCContext({ session }), transformer: superjson, }); const userData = await helpers.user.getUserData.fetch(); return { props: userData, }; });
withSession工具函数
function withSession<T>( getServerSideProps: ( session: Session, ctx: GetServerSidePropsContext ) => Promise<T> ) { return async (context: GetServerSidePropsContext) => { const session = await getServerAuthSession(context); if (!session) return { redirect: { destination: "/signin", permanent: false, }, }; return await getServerSideProps(session, context); }; }
解决方案
1. 全局覆盖缓存头配置
当前headers仅针对/myapp/:route生效,需扩展到所有路由,同时增强缓存禁用规则:
修改next.config.js中的headers配置:
headers: async () => [ { source: "/:path*", // 匹配所有路由 headers: [ { key: "Cache-Control", value: "no-store, no-cache, must-revalidate, proxy-revalidate", }, { key: "x-middleware-cache", value: "no-cache", }, { key: "Pragma", value: "no-cache", }, { key: "Expires", value: "0", }, ], }, ],
2. 禁用客户端路由缓存
Next.js的客户端路由默认会缓存页面数据,需显式禁用:
- 路由切换时添加
shallow: false参数:
router.push('/target-path', undefined, { shallow: false })
- 在Link组件中禁用预取缓存:
<Link href="/target-path" prefetch={false}>目标页面</Link>
3. 强化getServerSideProps的缓存控制
将getServerSideProps中的缓存头设置为更严格的规则:
ctx.res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); ctx.res.setHeader("Pragma", "no-cache"); ctx.res.setHeader("Expires", "0");
4. 清除TRPC客户端缓存
用户信息更新后,手动清除TRPC对应查询的缓存,确保路由切换时重新拉取数据:
// 在用户信息更新的TRPC调用完成后执行 await utils.user.getUserData.invalidate();
5. 检查Vercel边缘缓存设置
登录Vercel项目后台,进入「Edge Network」→「Caching」页面,确认没有全局缓存规则覆盖页面的Cache-Control配置,必要时针对特定路径设置缓存规则为no-store。
内容的提问来源于stack exchange,提问作者yeonhwan619
相关产品推荐
相关产品推荐

