Next.js getServerSideProps报window未定义 如何持久化存储payload
报错根因
getServerSideProps 是Next.js框架中仅在服务端Node.js环境运行的逻辑,执行阶段没有浏览器提供的window全局对象,直接在这个函数里调用window.localStorage必然触发ReferenceError: window is not defined。
可行解决方案
方案1:通过props透传数据,在客户端生命周期写入localStorage
这是改动最小、最符合Next.js执行逻辑的方案:
- 移除
getServerSideProps中直接调用storePersistence的服务端存储逻辑,把需要持久化的payload序列化后加入返回的props中,传递给前端页面组件。 - 在页面组件内使用
useEffect钩子执行存储逻辑——useEffect内的代码只会在浏览器端hydration完成后执行,可正常访问window对象。
修改后的getServerSideProps代码:
//@ts-ignore export async function getServerSideProps({ req, res, query }) { const { id } = query const cookies = Cookies(req, res) const jwt = cookies.get('lit-auth') if (!jwt) { return { props: { authorized: false, persistencePayload: null }, } } const { verified, payload } = LitJsSdk.verifyJwt({ jwt }) if ( payload.baseUrl !== "http://localhost:3000" || payload.path !== '/protected' || payload.extraData !== id ) { return { props: { authorized: false, persistencePayload: null }, } } return { props: { authorized: !!verified, // 序列化后传递,避免服务端到客户端的序列化异常 persistencePayload: verified ? JSON.stringify(payload) : null }, } }
页面组件内添加客户端存储逻辑:
import { useEffect } from 'react' import type { InferGetServerSidePropsType } from 'next' export default function ProtectedPage({ authorized, persistencePayload }: InferGetServerSidePropsType<typeof getServerSideProps>) { // 仅在客户端执行存储 useEffect(() => { if (persistencePayload) { window.localStorage.setItem('lit_protocols_jwt', persistencePayload) } }, [persistencePayload]) // 原有页面渲染逻辑 return <div>{authorized ? '已授权' : '未授权'}</div> }
方案2:直接通过Set-Cookie写入浏览器持久化(更推荐鉴权场景使用)
你当前代码已经在服务端操作Cookie,完全可以直接在服务端校验通过后,把payload写入响应Cookie,浏览器收到响应后会自动持久化存储,不需要额外写客户端JS逻辑:
// 在校验通过的位置直接调用cookies.set即可,不需要访问window cookies.set('lit_protocols_jwt', JSON.stringify(payload), { path: '/', // 7天过期,可按需调整 expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 如果需要前端JS读取Cookie就设为false,仅服务端读取设为true可防XSS窃取,安全性更高 httpOnly: false })
注意:鉴权类敏感数据优先选择Cookie+httpOnly配置,安全性远高于localStorage。
方案选型参考
- 如果存储的数据仅在前端业务逻辑中使用、不需要随请求自动上报,选方案1(localStorage),存储容量更大,不会额外增加请求体积。
- 如果存储的是鉴权凭证、需要后续请求自动携带,选方案2(Cookie),实现更简单,安全配置更灵活。
内容的提问来源于stack exchange,提问作者NextNightFlyer
相关产品推荐
相关产品推荐

