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请求:
- 修改
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(); };
- 在服务器组件中传递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
相关产品推荐
相关产品推荐

