Next.js 13中调用redirect跳转时触发NEXT_REDIRECT错误排查
问题分析与解决方法
错误原因
- 在服务端组件中使用客户端鉴权监听:你的
Home组件是异步函数,在Next.js App Router中默认属于服务端组件。而onAuthStateChanged是Firebase的客户端API,依赖浏览器环境运行,不能在服务端组件中调用。 - 在异步回调中调用
redirect():Next.js的redirect()函数必须在组件初始渲染流程中执行。但onAuthStateChanged的回调是异步触发的,会在组件开始渲染后才运行,此时调用redirect()就会抛出NEXT_REDIRECT错误。
修复方案(客户端组件实现)
将组件标记为客户端组件,使用React状态跟踪用户鉴权状态,并通过useRouter完成重定向:
'use client'; import { useEffect, useState } from 'react'; import { onAuthStateChanged } from 'firebase/auth'; import { auth } from '../src/firebaseConfig'; import { useRouter } from 'next/navigation'; export default function Home() { const [user, setUser] = useState(null); const router = useRouter(); useEffect(() => { // 订阅鉴权状态变化 const unsubscribe = onAuthStateChanged(auth, (authUser) => { setUser(authUser); if (!authUser) { router.replace('/login'); } }); // 组件卸载时取消订阅,避免内存泄漏 return unsubscribe; }, [router]); // 鉴权状态未确定时显示加载中 if (user === null) { return <div>加载中...</div>; } // 已登录用户的页面内容 return ( <div> <h1>首页</h1> <p>欢迎回来,{user.email}!</p> </div> ); }
更安全的方案(服务端中间件)
如果需要更高的安全性,建议使用Next.js中间件在服务端提前校验用户身份,避免客户端鉴权被绕过:
创建项目根目录下的middleware.ts文件:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { getAuth } from 'firebase-admin/auth'; import { initializeApp, getApps } from 'firebase-admin/app'; // 初始化Firebase Admin SDK(仅初始化一次) if (!getApps().length) { initializeApp({ credential: getAuth().credential.cert({ projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, clientEmail: process.env.FIREBASE_CLIENT_EMAIL, privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'), }), }); } export async function middleware(request: NextRequest) { // 获取客户端存储的会话Cookie const sessionCookie = request.cookies.get('__session')?.value; try { if (sessionCookie) { // 校验会话Cookie的有效性 await getAuth().verifySessionCookie(sessionCookie, true); // 校验通过,允许访问页面 return NextResponse.next(); } } catch (err) { // Cookie无效,重定向到登录页 return NextResponse.redirect(new URL('/login', request.url)); } // 无有效会话,重定向到登录页 return NextResponse.redirect(new URL('/login', request.url)); } // 指定需要保护的路由 export const config = { matcher: ['/', '/dashboard/:path*'], // 添加你的受保护路由 };
注意:使用中间件方案时,需要在客户端登录后通过API路由创建并设置会话Cookie,具体可参考Firebase官方文档中关于会话Cookie的说明。
内容的提问来源于stack exchange,提问作者mikkolikoli
相关产品推荐
相关产品推荐

