Next-auth:设置请求头或Body时getSession返回null的问题
Next.js + NextAuth POST请求带Body/Header时getSession返回null的问题
问题现象
使用NextAuth实现认证时:
- GET请求或不带
Content-Type头、无Body的POST请求中,服务端调用await getSession({ req })能正常返回session数据 - 当POST请求添加
Content-Type: application/json头及JSON格式Body后,getSession返回null - 临时测试发现:先复制
req.body再删除它,就能正常获取session
异常请求示例:
const response = await fetch("/api/shops", { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ shopName: shopName, description: description }), });
NextAuth配置文件([...nextauth].js):
import NextAuth from "next-auth"; import CredentialsProvider from "next-auth/providers/credentials"; import mongoDbClient from "../../../lib/mongodb"; import bcrypt from "bcryptjs"; export default NextAuth({ providers: [ CredentialsProvider({ name: "Credentials", credentials: { email: { label: "email", type: "text" }, password: { label: "Password", type: "password" }, }, async authorize(credentials, req) { const db = (await mongoDbClient).db(process.env.MONGODB_DBNAME); const usersCollection = db.collection("users"); const user = await usersCollection.findOne({ email: credentials.email, }); if (user && bcrypt.compareSync(credentials.password, user.password)) { delete user.password; return user; } else { throw new Error('Invalid credentials'); } }, }), ], session: { jwt: true, }, jwt: { secret: process.env.JWT_SECRET, }, callbacks: { async jwt({ token, user }) { if (user) { token.user = user; } return token; }, async session({ session, token }) { if (token.user) { session.user = token.user; } return session; }, }, });
原因分析
这不属于预期行为,本质是Next.js API路由的自动body解析机制与NextAuth的getSession方法对req对象的处理冲突:
- 当请求带有
Content-Type: application/json时,Next.js会自动解析请求体并挂载到req.body,这个过程会修改req对象的内部状态(比如消耗请求流、修改可读状态) - NextAuth的
getSession内部需要读取请求的原始头信息(包括认证cookie),但req被自动解析body后,部分内部状态变化导致NextAuth无法正确提取session数据
解决方案
方案1:先调用getSession再处理req.body
调整代码顺序,确保获取session的操作在读取req.body之前执行:
export default async function handler(req, res) { // 优先获取session const session = await getSession({ req }); if (!session) { res.status(401).json({ error: "Unauthorized" }); return; } // 再处理请求体 const { shopName, description } = req.body; // 后续业务逻辑 // ... }
方案2:使用getToken替代getSession
由于你使用的是JWT模式的session,直接调用getToken方法可以绕过req.body解析的冲突,更直接地获取用户认证信息:
import { getToken } from "next-auth/jwt"; export default async function handler(req, res) { // 直接获取JWT token const token = await getToken({ req, secret: process.env.JWT_SECRET }); if (!token) { res.status(401).json({ error: "Unauthorized" }); return; } // token中包含用户信息,可直接使用 const { shopName, description } = req.body; // 后续业务逻辑 // ... }
方案3:禁用自动body解析,手动解析
通过API路由配置禁用Next.js的自动body解析,手动处理请求体,避免req对象被提前修改:
// 禁用自动body解析 export const config = { api: { bodyParser: false, }, }; export default async function handler(req, res) { let body = {}; // 手动解析JSON格式的请求体 if (req.method === "POST" && req.headers["content-type"] === "application/json") { body = await new Promise((resolve, reject) => { let rawData = ""; req.on("data", (chunk) => (rawData += chunk)); req.on("end", () => { try { resolve(JSON.parse(rawData)); } catch (err) { reject(err); } }); req.on("error", reject); }); } // 获取session const session = await getSession({ req }); if (!session) { res.status(401).json({ error: "Unauthorized" }); return; } // 使用解析后的body const { shopName, description } = body; // 后续业务逻辑 // ... }
内容的提问来源于stack exchange,提问作者Emmanuel Amodu
相关产品推荐
相关产品推荐

