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

Next.js生产环境getServerSideProps重定向失效问题求助

Next.js SSR认证重定向生产环境失效问题(Service Worker缓存导致)

问题背景

用Next.js开发的SSR认证系统,生产环境执行next start后,偶尔出现getServerSideProps重定向逻辑失效:已登出用户访问需要认证的页面时,不会跳转到登录页,刷新页面可临时恢复正常。

核心代码

认证高阶函数withAuthServerSideProps

export const withAuthServerSideProps = (props?: WithServerSideAuthParams) => {
  return async (context: GetServerSidePropsContext) => {
    const {
      getServerSidePropsFunc,
      redirectCondition,
      requiredRole,
      route = '/signin',
    } = props || {};
    const response = await getUserData(context);
    const isAuthed = !!response?.data;
    let shouldRedirect;
    switch (redirectCondition) {
      case 'isInfluencer':
        shouldRedirect = isAuthed && response.data.role === Roles.INFLUENCER;
        break;
      case 'isAuthed':
        shouldRedirect = isAuthed;
        break;
      case 'isNotAuthed':
        shouldRedirect = !isAuthed;
        break;
      case 'noRedirect':
        shouldRedirect = false;
        break;
    }
    if (
      shouldRedirect ||
      (requiredRole && requiredRole !== response?.data?.role)
    ) {
      return {
        redirect: {
          destination: route,
          permanent: false,
        },
      };
    }
    // 执行自定义SSR逻辑(如果有)
    if (getServerSidePropsFunc) {
      try {
        const funcData = await getServerSidePropsFunc(context);
        return {
          props: {
            data: funcData,
            user: response?.data ?? null,
          },
        };
      } catch (e) {
        console.log(e);
        return {
          props: {
            data: null,
            user: response?.data ?? null,
          },
        };
      }
    }
    return {
      props: {
        user: response?.data ?? null,
      },
    };
  };
};

页面调用示例(InfluencerPage)

export const getServerSideProps = withAuthServerSideProps({
  getServerSidePropsFunc,
});

export default InfluencerPage;

观察到的异常:Service Worker返回的响应不含重定向信息,但服务器实际返回了正确的重定向响应,却未触发页面跳转,怀疑是Service Worker缓存了旧的页面内容。


解决方案

1. 禁用不必要的Service Worker

如果应用不需要离线支持或静态资源缓存,可以直接禁用Next.js默认的Service Worker:
在next.config.js中添加配置:

module.exports = {
  // 禁用Service Worker(适用于Next.js内置PWA或next-pwa插件)
  pwa: {
    disable: true,
  },
};

2. 配置Service Worker排除认证页面缓存

如果需要保留Service Worker,需确保认证相关页面(需登录的页面、登录页)强制走网络请求,不被缓存:
以next-pwa插件为例,修改next.config.js的runtimeCaching规则:

const withPWA = require('next-pwa')({
  dest: 'public',
  runtimeCaching: [
    // 其他静态资源缓存规则...
    // 排除认证相关路由,强制网络优先
    {
      urlPattern: /^https?:\/\/your-domain\/(signin|dashboard|influencer)/, // 替换为你的认证路由
      handler: 'NetworkFirst',
      options: {
        cacheName: 'auth-pages',
        expiration: {
          maxEntries: 0, // 不缓存任何条目
          maxAgeSeconds: 0,
        },
      },
    },
  ],
});

module.exports = withPWA({
  // 其他Next.js配置
});

3. 登出时主动清理缓存并更新Service Worker

在登出逻辑中,手动清除相关缓存并触发Service Worker更新,确保下次请求走服务器:

async function handleLogout() {
  // 执行登出接口请求
  await fetch('/api/logout', { method: 'POST' });

  // 清除认证相关缓存
  if ('caches' in window) {
    const cacheNames = await caches.keys();
    for (const name of cacheNames) {
      if (name.includes('auth-pages')) await caches.delete(name);
    }
  }

  // 更新Service Worker并跳过等待
  if ('serviceWorker' in navigator) {
    const registrations = await navigator.serviceWorker.getRegistrations();
    for (const reg of registrations) {
      await reg.update();
      reg.waiting?.postMessage({ type: 'SKIP_WAITING' });
    }
  }

  // 强制跳转登录页
  window.location.href = '/signin';
}

4. 给SSR响应添加禁止缓存头

在withAuthServerSideProps中设置响应头,明确告诉浏览器和Service Worker不要缓存该页面:

export const withAuthServerSideProps = (props?: WithServerSideAuthParams) => {
  return async (context: GetServerSidePropsContext) => {
    // 添加缓存控制头,禁止任何缓存
    context.res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
    context.res.setHeader('Pragma', 'no-cache');
    context.res.setHeader('Expires', '0');

    // 原有的认证逻辑...
    const response = await getUserData(context);
    // ...后续代码不变
  };
};

验证方法

  1. 打开Chrome DevTools → Application标签,查看Service Workers确认没有异常缓存的页面。
  2. 查看Cache Storage,确认认证相关路由没有被缓存。
  3. 登出后重新访问需要认证的页面,查看网络请求是否直接发送到服务器,而非读取Service Worker缓存。

内容的提问来源于stack exchange,提问作者Oddwerth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 02:50:26