Next.js服务端函数用redirect时遇NEXT_REDIRECT错误求助
Next.js 中使用
redirect 函数出现 NEXT_REDIRECT 错误的解决方案 我正在开发一个 Next.js 应用,有一个处理用户登录的表单。登录成功后,我想用 next/navigation 中的 redirect 函数做服务端重定向,但碰到了下面的错误:
Sign-in error: Error: NEXT_REDIRECT at getRedirectError (redirect.js:49:19) at redirect (redirect.js:60:11) at handleSignIn (cognitoActions.ts:87:13) at async eval (login-form.tsx:38:34)
我的代码结构
LoginForm 组件
import React, { useTransition } from 'react' import { Button } from '../button' import { Input } from '../input' import Link from 'next/link' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import { TLoginSchema } from '@/lib/types/LoginSchema' import { loginSchema } from '@/lib/schemas/login' import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form' import { handleSignIn } from '@/lib/cognitoActions' export default function LoginForm() { const [pending, startTransition] = useTransition() const form = useForm<TLoginSchema>({ resolver: zodResolver(loginSchema), defaultValues: { email: '', password: '', }, }) function onSubmit(values: TLoginSchema) { startTransition(async () => { try { const response = await handleSignIn(undefined, values) console.log('Sign-in response:', response) } catch (error) { console.error('Sign-in error:', error) } }) } return ( <Form {...form}> <form className='flex flex-col justify-between gap-8 min-w-[450px]' onSubmit={form.handleSubmit(onSubmit)}> <h1>Chat Inmobiliario</h1> <FormField control={form.control} name='email' render={({ field }) => ( <FormItem> <FormLabel>Email</FormLabel> <FormControl> <Input type='email' {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <FormField control={form.control} name='password' render={({ field }) => ( <FormItem> <FormLabel>Contraseña</FormLabel> <FormControl> <Input type='password' {...field} /> </FormControl> <FormMessage /> </FormItem> )} /> <Button size='lg' type='submit' disabled={pending}> {pending ? 'Ingresando...' : 'Ingresar'} </Button> </form> </Form> ) }
handleSignIn 函数
import { signUp, confirmSignUp, autoSignIn, resendSignUpCode, signIn, signOut } from 'aws-amplify/auth' import { TLoginSchema } from './types/LoginSchema' import { TSignUpSchema } from './types/SignUpSchema' import { getErrorMessage } from '@/utils/get-error-message' import { redirect } from 'next/navigation' import { TConfirmSignupSchema } from './types/ConfirmSignupSchema' export async function handleSignIn(prevState: string | undefined, formData: TLoginSchema) { let redirectLink = '/dashboard' try { const { isSignedIn, nextStep } = await signIn({ username: String(formData.email), password: String(formData.password), }) if (nextStep.signInStep === 'CONFIRM_SIGN_UP') { console.log(nextStep.signInStep) await resendSignUpCode({ username: String(formData.email), }) redirectLink = '/auth/confirm-signup' } } catch (error) { return getErrorMessage(error) } console.log('Redirecting to:', redirectLink) redirect(redirectLink) }
尽管是在服务端上下文使用 redirect,我仍遇到 NEXT_REDIRECT 错误。请问如何正确处理服务端重定向避免该错误?我的实现哪里出错了?
问题根源与解决方案
问题核心是:redirect 函数仅适用于 Server Components、Server Actions 或 Route Handlers 的服务端执行上下文,而你当前是在客户端组件的 onSubmit 逻辑中直接调用它。redirect 会抛出特殊的 NEXT_REDIRECT 错误来触发重定向,但客户端环境无法处理这个错误,因此会被你的 catch 块捕获,导致重定向失效。
修正方案
方案1:将 handleSignIn 改为 Server Action
Next.js 的 Server Action 允许在客户端组件中调用服务端代码,并且能正确处理 redirect 抛出的错误,只需给函数添加 'use server' 指令:
修改 handleSignIn 函数:
'use server' // 新增服务端指令 import { signUp, confirmSignUp, autoSignIn, resendSignUpCode, signIn, signOut } from 'aws-amplify/auth' import { TLoginSchema } from './types/LoginSchema' import { TSignUpSchema } from './types/SignUpSchema' import { getErrorMessage } from '@/utils/get-error-message' import { redirect } from 'next/navigation' import { TConfirmSignupSchema } from './types/ConfirmSignupSchema' export async function handleSignIn(prevState: string | undefined, formData: TLoginSchema) { let redirectLink = '/dashboard' try { const { isSignedIn, nextStep } = await signIn({ username: String(formData.email), password: String(formData.password), }) if (nextStep.signInStep === 'CONFIRM_SIGN_UP') { console.log(nextStep.signInStep) await resendSignUpCode({ username: String(formData.email), }) redirectLink = '/auth/confirm-signup' } } catch (error) { return getErrorMessage(error) } console.log('Redirecting to:', redirectLink) redirect(redirectLink) }
同时修改 LoginForm 的 onSubmit,无需手动捕获错误(Next.js 会自动处理 redirect 触发的错误):
function onSubmit(values: TLoginSchema) { startTransition(async () => { const response = await handleSignIn(undefined, values) if (response) { // 仅处理登录失败的错误信息 console.error('Sign-in error:', response) } }) }
方案2:客户端重定向替代(非服务端场景可选)
如果无法使用 Server Action,可在客户端用 useRouter 实现跳转(此方式为客户端跳转,非服务端重定向,仅适合无需服务端验证的场景):
- 在 LoginForm 中导入
useRouter:
import { useRouter } from 'next/navigation'
- 组件内初始化路由实例:
const router = useRouter()
- 修改
handleSignIn,返回重定向路径而非调用redirect:
export async function handleSignIn(prevState: string | undefined, formData: TLoginSchema) { let redirectLink = '/dashboard' try { const { isSignedIn, nextStep } = await signIn({ username: String(formData.email), password: String(formData.password), }) if (nextStep.signInStep === 'CONFIRM_SIGN_UP') { console.log(nextStep.signInStep) await resendSignUpCode({ username: String(formData.email), }) redirectLink = '/auth/confirm-signup' } return { redirect: redirectLink, error: null } } catch (error) { return { redirect: null, error: getErrorMessage(error) } } }
- 在
onSubmit中处理跳转:
function onSubmit(values: TLoginSchema) { startTransition(async () => { const result = await handleSignIn(undefined, values) if (result.error) { console.error('Sign-in error:', result.error) } else if (result.redirect) { router.push(result.redirect) } }) }
关键注意点
- 服务端
redirect函数只能在服务端执行上下文中使用,Server Action 是客户端组件调用服务端代码的合法方式。 - 不要在客户端代码中捕获
NEXT_REDIRECT错误,否则会阻止重定向触发。 - 若需处理登录错误,让 Server Action 返回错误信息即可,无需在服务端抛出普通错误(除非需要统一错误处理)。
内容的提问来源于stack exchange,提问作者Rai
相关产品推荐
相关产品推荐

