NextJS中间件中无法访问Response Cookie的问题求助
问题描述
在Next.js中间件中无法访问登录接口返回的Response Cookie:
- 当
/api/auth/login接口登录成功时,会在Response中设置tokenCookie,客户端能正常看到该Cookie - 但在中间件中通过
NextResponse.next()获取的Response里,response.cookies.get('token')和headers.get('Set-Cookie')均返回undefined或null
执行日志:
POST /api/auth/login 200 in 12080ms response.cookies.get('token') undefined headers.get('Set-Cookie') null POST /login 303 in 16313ms response.cookies.get('token') undefined headers.get('Set-Cookie') null
相关代码:
./middleware.ts
import { NextRequest, NextResponse } from "next/server"; import { cookies } from "next/headers"; import { parse } from 'cookie'; export function middleware(request: NextRequest) { const response = NextResponse.next({ request: { headers: request.headers, }, }); const token1 = response.cookies.get('token'); console.log("response.cookies.get('token')", token1) const { headers } = response; const token2 = headers.get('Set-Cookie'); console.log("headers.get('Set-Cookie')", token2) return response; }
./app/api/auth/login/route.ts
import { NextResponse } from 'next/server'; import jwt from 'jsonwebtoken'; import { fetchUser } from '@/lib/data'; export async function POST(request: Request) { const { email, pnum } = await request.json(); const pnum_matches = pnum.match(/[Pp]?(\d{1,})/); if (!pnum_matches) { return NextResponse.json({ message: 'Invalid participant number' }, { status: 400 }); } const pnum_match = pnum_matches[1]; const secretKey = process.env.SECRET_KEY; if (!secretKey) { return NextResponse.json({ message: 'Internal Server Error' }, { status: 500 }); } const user = await fetchUser(email, pnum_match); if (user && user.length > 0) { const token = jwt.sign({ email, pnum }, secretKey, { expiresIn: '3h' }); const response = NextResponse.json({ message: 'Authentication successful' }, { status: 200 }); response.cookies.set({ name: 'token', value: token, httpOnly: true, secure: process.env.NODE_ENV === 'production', maxAge: 60 * 60, path: '/', }); return response; } else { return NextResponse.json({ message: 'Authentication failed' }, { status: 401 }); } }
原因分析
核心误解在于Next.js中间件的执行逻辑:
NextResponse.next()创建的是空白的、允许请求向下游路由传递的响应对象,此时下游的登录接口还未执行,自然不会包含其设置的Cookie- 中间件运行在请求到达目标路由之前,当前代码无法获取后续路由返回的响应内容
解决方案
根据需求分两种场景处理:
场景1:验证登录后的请求Cookie
如果目的是在用户登录后的页面/接口请求中校验token,直接从请求对象读取即可(浏览器会自动携带已设置的Cookie):
// 修改后的middleware.ts import { NextRequest, NextResponse } from "next/server"; export function middleware(request: NextRequest) { // 从请求中读取已存在的Cookie const token = request.cookies.get('token'); // 示例:无token时重定向到登录页(排除登录接口本身) if (!token && !request.nextUrl.pathname.startsWith('/api/auth/login')) { return NextResponse.redirect(new URL('/login', request.url)); } return NextResponse.next(); }
场景2:拦截登录接口响应读取Cookie
如果需要直接获取登录接口返回的Cookie,需手动代理请求到登录接口,拿到原始响应后再处理:
// 修改后的middleware.ts import { NextRequest, NextResponse } from "next/server"; export async function middleware(request: NextRequest) { // 仅拦截登录接口的POST请求 if (request.nextUrl.pathname === '/api/auth/login' && request.method === 'POST') { // 代理请求到登录接口,获取原始响应 const rawResponse = await fetch(new URL('/api/auth/login', request.url), { method: request.method, headers: request.headers, body: request.body, credentials: 'same-origin' }); // 读取原始响应的Set-Cookie头 const setCookieHeader = rawResponse.headers.get('Set-Cookie'); console.log('Set-Cookie:', setCookieHeader); // 创建新响应返回给客户端,保留原始响应的内容和Cookie const newResponse = new NextResponse(rawResponse.body, { status: rawResponse.status, headers: rawResponse.headers }); return newResponse; } return NextResponse.next(); }
注意事项
httpOnlyCookie无法被前端JS读取,但中间件/服务端可正常从请求中获取- 生产环境务必开启
secure: true,确保Cookie仅通过HTTPS传输 - 建议在
next.config.js或middleware文件顶部配置matcher,避免不必要的请求被拦截
内容的提问来源于stack exchange,提问作者yoonjae
相关产品推荐
相关产品推荐

