Next.js:重定向后首次渲染getServerSideProps无法获取Cookie
问题场景
在Next.js应用中,通过服务端API设置Cookie并执行重定向:
res.setHeader('Set-Cookie', AJWT) res.redirect(302, '/')
在index.js中通过getServerSideProps尝试在页面渲染前获取Cookie:
export async function getServerSideProps(context) { let cookies = context.req.headers.cookie if (typeof cookies !== 'string') { return { props: { auth: false }, } } else { const { AJWT } = cookie.parse(cookies) return { props: { auth: AJWT ? true : false }, } } }
出现异常:重定向后的首次渲染无法获取Cookie,但刷新页面后可正常读取,且首次重定向后Cookie在开发者工具中可见。
原因分析
问题源于浏览器对302重定向的处理逻辑:当服务器返回Set-Cookie和302重定向响应时,浏览器会先保存Cookie,但紧随其后的重定向请求(跳转到/的请求)并不会自动携带刚设置的Cookie——因为这个跳转请求是在浏览器完成Cookie存储之前发起的,导致getServerSideProps处理首次跳转请求时,无法从req.headers.cookie中读取到新设置的Cookie。而刷新页面时,浏览器已完成Cookie持久化,会自动在请求头中携带Cookie,因此getServerSideProps能正常读取。
解决方案
方案1:改用客户端重定向
先让服务器返回Set-Cookie和成功响应,再在客户端执行重定向,确保浏览器先保存Cookie再发起跳转请求。
修改API路由代码:
// 确保设置完整的Cookie属性,Path=/保证所有根路径请求都携带Cookie res.setHeader('Set-Cookie', `${AJWT}; Path=/; HttpOnly; Secure`) res.status(200).json({ redirectUrl: '/' })
前端调用API后处理重定向(示例:登录组件中):
const handleLogin = async () => { const response = await fetch('/api/login', { method: 'POST', body: formData }) const { redirectUrl } = await response.json() if (redirectUrl) { window.location.href = redirectUrl } }
方案2:使用307重定向替代302
307临时重定向会要求浏览器保留原始请求方法和Header,且会正确携带刚设置的Cookie(部分浏览器对302的处理存在此兼容性问题,307的行为更严格规范)。
修改API路由代码:
res.setHeader('Set-Cookie', `${AJWT}; Path=/; HttpOnly; Secure`) res.redirect(307, '/')
方案3:服务器端直接渲染目标页面(跳过重定向)
如果设置Cookie的逻辑和目标页面属于同一服务,可以在API路由中完成Cookie设置后,直接调用目标页面的渲染逻辑,避免客户端重定向流程。
示例API路由代码:
import { getServerSideProps } from '../pages/index' export default async function handler(req, res) { // 设置Cookie res.setHeader('Set-Cookie', `${AJWT}; Path=/; HttpOnly; Secure`) // 调用首页的getServerSideProps逻辑,确保服务端能拿到Cookie并返回正确props await getServerSideProps({ req, res }) // 用307重定向到首页,确保Cookie生效 res.redirect(307, '/') }
关键注意点
- 必须设置
Path=/,确保所有根路径下的请求都会携带该Cookie; - 生产环境使用HTTPS时,添加
Secure属性,确保Cookie仅在HTTPS下传输; - 若不需要前端JS读取Cookie,添加
HttpOnly属性提升安全性。
内容的提问来源于stack exchange,提问作者Slowfound

