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); // ...后续代码不变 }; };
验证方法
- 打开Chrome DevTools →
Application标签,查看Service Workers确认没有异常缓存的页面。 - 查看
Cache Storage,确认认证相关路由没有被缓存。 - 登出后重新访问需要认证的页面,查看网络请求是否直接发送到服务器,而非读取Service Worker缓存。
内容的提问来源于stack exchange,提问作者Oddwerth
相关产品推荐
相关产品推荐

