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

Next.js 14:中间件设置Cookie后根布局无法获取的问题

问题:Next.js 14中Middleware设置Cookie后首次加载根布局无法读取

环境依赖

  • react: 18.2.0
  • next: 14.0.3

需求目标

确保请求初始阶段就存在带SessionId的Cookie,通过Middleware实现。

实现代码

Middleware代码

export async function middleware(req: NextRequest) {
  const response = NextResponse.next();
  const ensuredSessionId = await fetchEnsureSession(
    req.nextUrl.origin,
    currentSessionId,
  );
  console.log(`ensured sessionid for url ${req.url}`, ensuredSessionId);
  response.cookies.set("sessionid", ensuredSessionId, {
    path: "/",
    httpOnly: true,
    sameSite: "strict",
    secure: true,
  });

  return response;
}

根布局代码

import { CartProvider } from "@storefront/shell/cart/cartcontext";
import { cookies } from "next/headers";

interface Props {
  children: React.ReactNode;
}

export default async function RootLayout({ children }: Props) {
  const session = cookies().get("sessionid");

  console.log("session-Id", session);

  return (
    <CartProvider sessionId={session?.value}>{children}</CartProvider>
  );
}

问题现象

首次加载页面时,根布局中读取sessionid Cookie的结果为undefined,但浏览器开发者工具能看到该Cookie已存在;刷新页面后,根布局就能正常获取到Cookie值。

Next.js日志

✓ Ready in 1773ms
✓ Compiled /src/middleware in 178ms (163 modules)
✓ Compiled /api/ensure-session in 455ms (33 modules)
ensured sessionId for url https://localhost:3000/en f142d570-93a7-4503-a52e-7f9fe580b89f
 ○ Compiling /[lang] ...
 ✓ Compiled /[lang] in 2.9s (3517 modules)
Session-Id undefined
 ○ Compiling /api/trpc/[trpc] ...
 ✓ Compiled /api/trpc/[trpc] in 573ms (2083 modules)

疑问

原本以为Middleware执行顺序在根布局之前,首次加载时Cookie应该已经存在,但实际并非如此。对Next.js Cookie机制的理解存在哪些误区?


解答

你核心的误区是混淆了Middleware设置Cookie的时机和服务器组件读取Cookie的来源:

  1. Middleware的执行逻辑:
    Middleware确实在根布局(服务器组件)执行前运行,但它是在处理当前请求的响应阶段设置Cookie——这个Cookie是要发送给浏览器的响应头内容,而非当前请求的请求头内容。

  2. 服务器组件读取Cookie的来源:
    根布局里用cookies().get("sessionid")读取的是当前请求从浏览器发送过来的Cookie(即请求头里的Cookie字段)。首次加载时,浏览器还没收到Middleware设置的Cookie,自然不会在请求头里带上,所以服务器组件读不到。

  3. 刷新后能读取的原因:
    首次加载的响应返回后,浏览器保存了这个Cookie;刷新页面时,浏览器会把该Cookie放在请求头里发送给服务器,此时服务器组件就能从请求头里读到这个Cookie了。

解决方法

方法1:Middleware传递SessionId到服务器组件

通过NextResponse.next()的headers属性,把SessionId作为自定义头传递,根布局直接读取这个自定义头:

修改Middleware:

export async function middleware(req: NextRequest) {
  const ensuredSessionId = await fetchEnsureSession(
    req.nextUrl.origin,
    currentSessionId,
  );
  const response = NextResponse.next({
    headers: {
      "x-session-id": ensuredSessionId,
    },
  });
  response.cookies.set("sessionid", ensuredSessionId, {
    path: "/",
    httpOnly: true,
    sameSite: "strict",
    secure: true,
  });
  return response;
}

修改根布局:

import { CartProvider } from "@storefront/shell/cart/cartcontext";
import { headers } from "next/headers";

interface Props {
  children: React.ReactNode;
}

export default async function RootLayout({ children }: Props) {
  const sessionId = headers().get("x-session-id");
  console.log("session-Id", sessionId);

  return (
    <CartProvider sessionId={sessionId}>{children}</CartProvider>
  );
}

方法2:服务器组件直接调用SessionId生成逻辑

既然Middleware里的fetchEnsureSession是用来确保SessionId存在的,直接在根布局里调用这个函数,跳过对Cookie的依赖:

import { CartProvider } from "@storefront/shell/cart/cartcontext";
import { cookies } from "next/headers";
import { fetchEnsureSession } from "path-to-your-function";

interface Props {
  children: React.ReactNode;
}

export default async function RootLayout({ children }: Props) {
  const currentSession = cookies().get("sessionid")?.value;
  const sessionId = await fetchEnsureSession(
    process.env.NEXT_PUBLIC_APP_URL,
    currentSession
  );

  console.log("session-Id", sessionId);

  return (
    <CartProvider sessionId={sessionId}>{children}</CartProvider>
  );
}

这样首次加载就能直接拿到SessionId,同时Middleware依然负责把Cookie设置到响应中,后续请求可复用该Cookie。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:48:27