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

Next.js客户端请求无法获取会话,RBAC路由配置遇阻

Next.js服务器组件调用API路由丢失Session问题的解决方案

问题根源

服务器组件运行在服务器端,当它发起fetch请求到内部API路由时,这个请求是服务器到服务器的,不会自动携带用户浏览器的Cookie(直接访问API路由时是浏览器发起请求,Cookie会自动附带)。所以即使加了credentials: "include",也无法拿到浏览器的Session信息。

解决方案

方案1:直接在服务器组件中处理业务逻辑(推荐)

既然服务器组件本身就在服务器端,完全可以跳过API路由,直接获取Session并查询数据库,既高效又避免Cookie传递问题:

import Link from "next/link";
import { getServerSession } from "next-auth/next";
import { authOptions } from "~/server/auth"; // 替换为你的authOptions实际路径
import prisma from "~/server/db"; // 替换为你的Prisma实例实际路径

const MyCoursesPage = async () => {
  const session = await getServerSession(authOptions);

  if (!session?.user) {
    return <div>failed to load, no session</div>;
  }

  // 直接查询数据库获取用户套餐
  const userPackages = await prisma.user.findUnique({
    where: { id: session.user.id },
    select: { packages: true },
  });

  if (!userPackages?.packages) {
    return <div>No courses found</div>;
  }

  return (
    <div className="flex h-screen text-red-500">
      <h1>My Courses</h1>
      <div className="flex flex-col">
        {userPackages.packages.map((item) => (
          <div key={item.id} className="mb-2">
            <Link href={`/package/${item.id}`}>{item.title}</Link>
          </div>
        ))}
      </div>
    </div>
  );
};

export default MyCoursesPage;

方案2:手动传递Cookie到API路由请求

如果一定要保留API路由的调用方式,需要将当前服务器组件请求的Cookie手动传递给内部fetch请求:

  1. 修改getUserPackages函数,支持接收请求头:
export const getUserPackages = async (headers: Headers) => {
  const response = await fetch(
    `${process.env.BASE_URL || "http://localhost:3000"}/api/user-packages`,
    {
      method: "GET",
      credentials: "include",
      headers: headers, // 传递包含Cookie的请求头
    }
  );

  return response.json();
};
  1. 在服务器组件中传递headers:
import Link from "next/link";
import { getUserPackages } from "~/server/api/user-packages";

const MyCoursesPage = async ({ headers }: { headers: Headers }) => {
  const packages = await getUserPackages(headers);

  if (packages.error) {
    return <div>failed to load, no session</div>;
  }

  return (
    <div className="flex h-screen text-red-500">
      <h1>My Courses</h1>
      <div className="flex flex-col">
        {packages.packages.map((item) => (
          <div key={item.id} className="mb-2">
            <Link href={`/package/${item.id}`}>{item.title}</Link>
          </div>
        ))}
      </div>
    </div>
  );
};

export default MyCoursesPage;

内容的提问来源于stack exchange,提问作者Pierre Olivier Tran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:24:54