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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:42:44