NextJS 13使用Next-Auth中间件时无限GET请求循环问题解决
问题已解决!
经排查,该问题由beta版turbopack导致,我已提交相关issue,等待官方修复。
问题描述
近期我使用NextJS 13的新app目录开发项目,集成了Prisma并连接MySQL数据库,之后安装了Next-Auth。用户创建及JWT认证功能均正常,但登录后访问受Next-Auth中间件保护的路由时,浏览器会陷入无限GET请求循环(见下图),导致站点失去响应,同时返回以下错误:
"Failed to fetch RSC payload. Falling back to browser navigation. TypeError: NetworkError when attempting to fetch resource."
备注:
移除middleware.ts文件后,路由保护功能会消失,但无限GET请求循环问题也会随之解决。
若需要更多信息协助排查,请告知。
截图:

代码:
projectDir\app\api\auth[...nextauth]\route.ts
// Imports import NextAuth from "next-auth/next"; import prisma from "@/lib/prisma"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; import CredentialsProvider from "next-auth/providers/credentials"; import { type NextAuthOptions } from "next-auth"; // NextAuth handler. export const authOptions: NextAuthOptions = { // Set adapter. adapter: PrismaAdapter(prisma), // Set secret. secret: process.env.NEXTAUTH_SECRET, // Set session strategy. session: { strategy: 'jwt' }, // Set different login providers. providers: [ CredentialsProvider({ // The name to display on the sign in form (e.g. "Sign in with...") name: "Credentials", // `credentials` is used to generate a form on the sign in page. // You can specify which fields should be submitted, by adding keys to the `credentials` object. // e.g. domain, username, password, 2FA token, etc. // You can pass any HTML attribute to the <input> tag through the object. credentials: { username: { label: "Email", type: "text", placeholder: "user@email.com" }, password: { label: "Password", type: "password" } }, async authorize(credentials) { // Create request to login api const res = await fetch("http://localhost:3000/api/login", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username: credentials?.username, password: credentials?.password, }), }); // Get response from request const user = await res.json(); if (res.ok && user) { // If request returns an user, return the user object received. return user } else { // If request does not return an user, return null. return null // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter } } }) ], callbacks: { // Callback for when a jwt is created or updated. async jwt({token, user}) { return({...token,...user}); }, // Callback for when a session is checked. async session({session, token}) { // Add token to session. session.user = token as any; return session; } } } const handler = NextAuth(authOptions); export { handler as GET, handler as POST}
projectDir\middleware.ts
export { default } from 'next-auth/middleware' export const config = { matcher: "/settings" }
projectDir\app\api\login\route.ts
// Imports import { signJwtAccessToken } from "@/lib/jwt"; import prisma from "@/lib/prisma"; import * as bcrypt from 'bcryptjs'; // Interface interface RequestBody { username: string; password: string; } // Return route. export async function POST(request: Request) { // Get requests body. const body: RequestBody = await request.json(); // Create const with requested user. const user = await prisma.user.findFirst({ where: { email: body.username, } }); // If user exists check if password is correct and return the user. if(user && ( await bcrypt.compare(body.password, user.password))) { // Remove password from user object in the response. const {password, ...userWithoutPass} = user // Create jwt. const accessToken = signJwtAccessToken(userWithoutPass); // Combine user with jwt as result. const result = { ...userWithoutPass, accessToken, } // Return the result as JSON object. return new Response(JSON.stringify(result)); } // Return null as JSON object. else return new Response(JSON.stringify(null)); }
projectDir\app\lib\jwt.ts
// Imports import jwt,{ JwtPayload } from "jsonwebtoken"; // Interfaces interface SignOption { expiresIn?: string | number, } // Default token expiration date. const DEFAULT_SIGN_OPTION:SignOption={ expiresIn: "1h" } // Function to create jwt. export function signJwtAccessToken(payload: JwtPayload, options: SignOption= DEFAULT_SIGN_OPTION) { // Get secret key. const secret_key = process.env.SECRET_KEY; // Create token. const token = jwt.sign(payload, secret_key!, options); // Return the token. return token; } // Function to verify jwt. export function verifyJwt(token: string) { try { // Get secret key. const secret_key = process.env.SECRET_KEY; // Verify secret key. const decoded = jwt.verify(token, secret_key!); // Return if jwt is valid return decoded as JwtPayload; } catch (error) { // If jwt is not valid, log the error. console.log(error); // And return null. return null; } }
已尝试的方案(均无效)
我尝试了以下方法,但均未解决问题:
- 降级Next.js、Next-Auth等依赖版本
- 移除自定义登录路由,使用预定义用户
- 移除Next-Auth的回调函数
- 将中间件应用到/settings以外的其他页面
- 重新安装node_modules
内容的提问来源于stack exchange,提问作者TheToughest
相关产品推荐
相关产品推荐

