You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 实现跳转(此方式为客户端跳转,非服务端重定向,仅适合无需服务端验证的场景):

  1. 在 LoginForm 中导入 useRouter:
import { useRouter } from 'next/navigation'
  1. 组件内初始化路由实例:
const router = useRouter()
  1. 修改 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) }
    }
}
  1. 在 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 14:07:02