Next.js生产环境设置Cookie后Middleware无法读取需刷新页面问题
在Next.js项目中,登录页面使用cookies-next库设置名为user的Cookie后,通过router.push跳转到目标页面,生产环境下Middleware无法读取该Cookie,必须刷新页面才能正常读取;但开发环境(npm run dev)无此问题。
设置Cookie的代码
import { getCookies, setCookie, deleteCookie, hasCookie } from 'cookies-next'; import { useRouter } from 'next/router'; export default function LoginPage() { const router = useRouter() const login = () => { if (hasCookie('user')) { router.push('/'); return; } setCookie('user', 'DHamidi-RandomValue') router.push('/'); } return <div className="layout"> <h2>Login</h2> <button onClick={login}> Add User Info To Cookie. </button> </div> }
Middleware读取Cookie的代码
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { if (request.cookies.has('user')) return NextResponse.next() return NextResponse.redirect(new URL('/login', request.nextUrl.clone())) } export const config = { matcher: '/admin/:path*', }
注:问题仅在生产环境(
npm run build=>npm run start)出现。
这是因为Next.js生产环境下的客户端路由跳转(router.push)属于SPA式导航,不会触发完整的HTTP请求到服务器,而Middleware是运行在服务器端的,它只能读取浏览器在HTTP请求头中携带的Cookie。
当你在客户端用cookies-next设置Cookie后直接调用router.push跳转,此时只是客户端内部的页面切换,浏览器不会向服务器发送新请求,Middleware自然无法获取到刚设置的Cookie——只有刷新页面时,浏览器才会在HTTP请求头中带上所有当前有效的Cookie,Middleware才能读取到。
开发环境中,Next.js的热重载机制或客户端路由的行为逻辑和生产环境存在差异,可能隐式触发了类似请求的同步行为,所以没有出现这个问题。
有两种常见方案可以解决这个问题:
改用服务器端设置Cookie后跳转
把登录逻辑放到API路由中,在API里设置Cookie并返回跳转响应,这样浏览器会在后续请求中自动带上Cookie:// pages/api/login.ts import { NextApiRequest, NextApiResponse } from 'next'; import { setCookie } from 'cookies-next'; export default function handler(req: NextApiRequest, res: NextApiResponse) { setCookie('user', 'DHamidi-RandomValue', { req, res }); res.redirect('/admin'); }登录页面的按钮改为调用该API,而非客户端设置Cookie后跳转。
改用
window.location.href触发完整跳转
如果坚持在客户端设置Cookie,可以用window.location.href替代router.push,这会触发完整的页面刷新,浏览器会带上新设置的Cookie:const login = () => { if (hasCookie('user')) { window.location.href = '/'; return; } setCookie('user', 'DHamidi-RandomValue') window.location.href = '/'; }缺点是会丢失SPA跳转的流畅性,但能确保Middleware读取到最新的Cookie。
内容的提问来源于stack exchange,提问作者Ghasem Khalili

