You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中间件中无法访问Response Cookie的问题求助

问题描述

在Next.js中间件中无法访问登录接口返回的Response Cookie:

  • 当/api/auth/login接口登录成功时,会在Response中设置token Cookie,客户端能正常看到该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();
}
注意事项
  • httpOnly Cookie无法被前端JS读取,但中间件/服务端可正常从请求中获取
  • 生产环境务必开启secure: true,确保Cookie仅通过HTTPS传输
  • 建议在next.config.js或middleware文件顶部配置matcher,避免不必要的请求被拦截

内容的提问来源于stack exchange,提问作者yoonjae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:46:20