Next.js中间件与Cookie不同步:登录后需刷新才能访问Admin页面
问题:Next.js生产环境登录后无法直接访问Admin路由,需刷新页面
我配置了Home、About、Contact、Admin四个路由,要求访问Admin页面必须先登录。但登录完成后直接跳转Admin页面会被拦截重定向到登录页,必须刷新页面才能正常进入。当前使用middleware校验Cookie是否存在,存在则允许访问,否则重定向到登录页,代码如下:
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { if (request.cookies.get('user')?.value) return NextResponse.next() return NextResponse.redirect(new URL('/login', request.url)) } export const config = { matcher: '/admin/:path*', }
问题仅在生产环境(执行npm run build → npm run start)出现,开发环境(npm run dev)完全正常。
原因
生产环境下Next.js会对客户端路由跳转做优化,跳转时不会发起完整的HTTP请求,而是复用现有请求上下文。登录后设置的Cookie属于新的浏览器状态,但middleware在客户端路由跳转时读取的仍是跳转前的旧Cookie上下文,因此会判定未登录并拦截。只有刷新页面时,才会发起全新的HTTP请求,middleware才能读取到最新的Cookie。
解决方案
1. 登录后改用服务端重定向
在登录接口中直接返回服务端重定向,触发完整HTTP请求,确保middleware读取最新Cookie:
// app/api/login/route.ts import { NextResponse } from 'next/server' export async function POST(request: Request) { // 处理登录逻辑,设置Cookie const response = NextResponse.redirect(new URL('/admin', request.url)) response.cookies.set('user', 'logged-in-user', { httpOnly: true }) return response }
2. 客户端跳转前刷新路由上下文
如果必须使用客户端跳转,登录成功后调用router.refresh()更新服务器组件上下文,再跳转Admin页面:
'use client' import { useRouter } from 'next/navigation' export default function LoginPage() { const router = useRouter() const handleLogin = async () => { // 发起登录请求,设置Cookie await fetch('/api/login', { method: 'POST', body: JSON.stringify({ username: 'xxx', password: 'xxx' }), headers: { 'Content-Type': 'application/json' } }) router.refresh() // 更新路由上下文,让middleware读取新Cookie router.push('/admin') } return <button onClick={handleLogin}>登录</button> }
3. 扩展middleware的匹配路径
让middleware拦截客户端路由跳转时的/_next/data/请求,这类请求会携带最新Cookie,确保校验逻辑生效:
export const config = { matcher: [ '/admin/:path*', '/_next/data/:path*/admin/:path*' // 匹配Admin路由的客户端数据请求 ], }
内容的提问来源于stack exchange,提问作者Ghasem Khalili
相关产品推荐
相关产品推荐

