Next.js14 headers调用超出请求域致聊天页无响应求助
问题原因
你在标记了"use client"的客户端组件里直接调用了NextAuth的auth()函数——这个函数仅能在服务器组件、API路由、Server Actions中使用,因为它需要访问请求上下文(如headers),而客户端环境没有这个上下文,因此触发headers was called outside a request scope错误,且由于异步逻辑重复执行,导致错误持续递增、页面无响应。
解决方案
提供两种可行修复方案,按需选择:
方案1:用客户端钩子获取会话+API路由取数据
1. 修改chats.tsx组件
替换await auth()为NextAuth客户端钩子useSession,并通过API请求获取聊天数据:
"use client"; import { useSession } from "next-auth/react"; import Chat from "./chat"; import { useState, useEffect } from "react"; import { IChatDocument } from "@/models/chatModel"; const Chats = () => { const [selectedChat, setSelectedChat] = useState<IChatDocument | null>(null); const [chats, setChats] = useState<IChatDocument[]>([]); const [loading, setLoading] = useState(true); const { data: session, status } = useSession(); useEffect(() => { const fetchChats = async () => { if (!session?.user?._id) { setLoading(false); return; } try { const res = await fetch(`/api/chats/${session.user._id}`); if (!res.ok) throw new Error("获取聊天列表失败"); const data = await res.json(); setChats(data); } catch (err) { console.error(err); } finally { setLoading(false); } }; if (status === "authenticated") fetchChats(); else if (status === "unauthenticated") setLoading(false); }, [session, status]); const handleSelectedChat = (chat: IChatDocument) => setSelectedChat(chat); if (loading) return <div>加载聊天中...</div>; return ( <nav> <ul> {chats.map((chat) => ( <Chat key={chat._id} chat={chat} handleSelectedChat={handleSelectedChat} selectedChat={selectedChat} /> ))} </ul> </nav> ); }; export default Chats;
2. 创建API路由处理数据请求
新建app/api/chats/[userId]/route.ts,在服务器环境中调用getUsersForSidebar:
import { getUsersForSidebar } from "@/lib/data"; import { NextResponse } from "next/server"; export async function GET(_: Request, { params }: { params: { userId: string } }) { try { const chats = await getUsersForSidebar(params.userId); return NextResponse.json(chats); } catch (err) { console.error(err); return NextResponse.json({ error: "获取聊天列表失败" }, { status: 500 }); } }
方案2:拆分组件,服务器端取数据+客户端处理状态
1. 新建服务器组件ChatsServer.tsx
负责在服务器环境中获取会话和聊天数据:
import { auth } from "@/auth"; import { getUsersForSidebar } from "@/lib/data"; import ChatsClient from "./ChatsClient"; export default async function ChatsServer() { const session = await auth(); const chats = session?.user ? await getUsersForSidebar(session.user._id) : []; return <ChatsClient chats={chats} />; }
2. 新建客户端组件ChatsClient.tsx
仅负责处理客户端状态和渲染:
"use client"; import Chat from "./chat"; import { useState } from "react"; import { IChatDocument } from "@/models/chatModel"; interface Props { chats: IChatDocument[]; } const ChatsClient = ({ chats }: Props) => { const [selectedChat, setSelectedChat] = useState<IChatDocument | null>(null); const handleSelectedChat = (chat: IChatDocument) => setSelectedChat(chat); return ( <nav> <ul> {chats.map((chat) => ( <Chat key={chat._id} chat={chat} handleSelectedChat={handleSelectedChat} selectedChat={selectedChat} /> ))} </ul> </nav> ); }; export default ChatsClient;
最后在页面中导入ChatsServer组件即可。
额外注意
- 确保
getUsersForSidebar函数仅包含服务器端可执行的逻辑(如数据库操作),不要混入客户端代码。 - 检查
auth.ts中的session回调,确认_id已正确添加到session对象中。
内容的提问来源于stack exchange,提问作者khayal
相关产品推荐
相关产品推荐

