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

Next.js 13中设置Cookie后无法在服务端/客户端组件中获取的问题排查求助

Next.js 13中设置Cookie后无法在服务端/客户端组件中获取的问题排查求助

我在Next.js v13开发认证功能时遇到了一个头疼的问题:我能成功把JWT Token存在Cookie里,但不管怎么尝试都没法在服务端组件和客户端组件里获取到它。我试了好几个Cookie处理库(比如cookie、js-cookie、cookies-next),甚至用了Next.js自带的next/headers里的cookies()方法,结果都是一样——要么拿到空对象、空数组,要么就是undefined。

登录接口代码(app/api/auth/loginUser/route.js)

import User from "@/app/_models/User";
import connectDB from "@/app/lib/connectdb";
import { AES, enc } from "crypto-js";
import { NextResponse } from "next/server";
import { sign } from "jsonwebtoken";
import { serialize } from "cookie";

const MAX_AGE = 60 * 60 * 24 * 2;

export async function POST(request) {
  try {
    connectDB();
    const { email, password } = await request.json();
    const user = await User.findOne({ email: email });

    if (!user)
      return new NextResponse(
        JSON.stringify({
          success: false,
          message: "Invalid credentials",
        })
      );

    const dycPassword = AES.decrypt(
      user.password,
      process.env.CRYPT_SECRET_KEY
    ).toString(enc.Utf8);

    if (dycPassword !== password) {
      return new NextResponse(
        JSON.stringify({
          success: false,
          message: "Invalid credentials",
        })
      );
    }

    const token = sign(user.toObject(), process.env.JWT_SECRET_KEY, {
      expiresIn: "2d",
    });

    const setCookie = serialize("userToken", token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "strict",
      maxAge: MAX_AGE,
      path: "/",
      httpOnly: false, // 这里重复设置了httpOnly,可能是笔误?
    });

    return new NextResponse(
      JSON.stringify({
        success: true,
        message: "Welcome!!!",
      }),
      { status: 200, headers: { "Set-Cookie": setCookie } }
    );
  } catch (error) {
    return new NextResponse(
      JSON.stringify({ success: false, message: error.message }),
      { status: 500 }
    );
  }
}

获取用户Token的接口(app/api/auth/me/route.js)

import { cookies } from "next/headers";
import { NextResponse } from "next/server";

export async function POST(req) {
  try {
    const cookieStore = cookies();
    const token = cookieStore.get("userToken");
    console.log(cookieStore.getAll(), token);
    return new NextResponse(
      JSON.stringify({ success: true, token: token }, { status: 200 })
    );
  } catch (error) {
    return new NextResponse(
      JSON.stringify({ success: false, message: error.message }),
      { status: 500 }
    );
  }
}

首页服务端组件(app/page.jsx)

import React from "react";
import { cookies } from "next/headers";

export const dynamic = "force-static";

export default async function Page() {
  const token = cookies().get("userToken");
  const data = await fetch("http://localhost:3000/api/auth/me", {
    method: "POST",
  }).then((data) => data.json());

  console.log(data);
  return (
    <div>
      <ul>{token}</ul>
    </div>
  );
}

项目依赖列表

"dependencies": {
  "@headlessui/react": "^1.7.17",
  "@heroicons/react": "^2.0.18",
  "cookie": "^0.5.0",
  "crypto-js": "^4.1.1",
  "jsonwebtoken": "^9.0.2",
  "mongoose": "^7.5.3",
  "next": "latest",
  "next-themes": "^0.2.1",
  "react": "latest",
  "react-dom": "latest",
  "react-switch": "^7.0.0",
  "react-toastify": "^9.1.3",
  "sass": "^1.68.0"
},
"devDependencies": {
  "autoprefixer": "latest",
  "eslint": "latest",
  "eslint-config-next": "latest",
  "postcss": "latest",
  "tailwindcss": "latest"
}

后续排查更新

我后来研究了请求头,发现问题出在Cookie根本没传到需要的页面里:

  • 用ThunderClient(VSCode的API测试插件)请求时,能正常拿到设置的Cookie;
  • 但在Chrome和Edge浏览器里,请求头是空的,完全看不到Cookie的影子;
  • 我写了个中间件打印请求头,中间件里能看到完整的请求内容(包括Cookie),但这些内容就是传不到服务端组件app/page.js里。

中间件代码(middleware.js)

import { NextResponse } from "next/server";

export async function middleware(request) {
  console.log(request.headers.get("cookie"));
  return NextResponse.next({
    request: {
      headers: new Headers(request.headers),
    },
  });
}

export const config = {
  matcher: "/",
};

页面app/page.js中拿到的Headers:

HeadersList {
  cookies: null,
  [Symbol(headers map)]: Map(0) {},
  [Symbol(headers map sorted)]: null
}

接口app/api/auth/me/route.js中拿到的Headers:

HeadersList {
  cookies: null,
  [Symbol(headers map)]: Map(10) {
    'accept' => { name: 'accept', value: '*/*' },
    'accept-encoding' => { name: 'accept-encoding', value: 'gzip, deflate' },
    'accept-language' => { name: 'accept-language', value: '*' },
    'cache-control' => { name: 'cache-control', value: 'no-cache' },
    'connection' => { name: 'connection', value: 'keep-alive' },
    'content-length' => { name: 'content-length', value: '0' },
    'host' => { name: 'host', value: 'localhost:3000' },
    'pragma' => { name: 'pragma', value: 'no-cache' },
    'sec-fetch-mode' => { name: 'sec-fetch-mode', value: 'cors' },
    'user-agent' => { name: 'user-agent', value: 'undici' }
  },
  [Symbol(headers map sorted)]: [
    [ 'accept', '*/*' ],
    [ 'accept-encoding', 'gzip, deflate' ],
    [ 'accept-language', '*' ],
    [ 'cache-control', 'no-cache' ],
    [ 'connection', 'keep-alive' ],
    [ 'content-length', '0' ],
    [ 'host', 'localhost:3000' ],
    [ 'pragma', 'no-cache' ],
    [ 'sec-fetch-mode', 'cors' ],
    [ 'user-agent', 'undici' ]
  ]
}

登录后的跳转逻辑(表单提交函数)

const handleSubmit = async (e) => {
  e.preventDefault();
  if (email == "" || password == "") {
    toast.error("Fill all the fields");
    return;
  }
  const res = await fetch("api/auth/loginUser", {
    method: "POST",
    cache: "no-store",
    body: JSON.stringify({ email, password }),
  }).then((data) => data.json());

  if (res.success) {
    toast.success(res.message);
    router.push("/");  // 登录成功后跳转到首页
  } else {
    toast.error(res.message);
  }
};

另外,我确认Cookie已经在浏览器里存储了,但就是没法在组件/接口里获取到。


备注:内容来源于stack exchange,提问作者Shashwat Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 12:18:00