Next SSR:如何重定向至登录页并传递登录失败错误数据
登录失败重定向时传递错误信息的实现方案
问题场景
开发登录页面时,需要在登录失败后重定向回当前登录页并展示错误提示,但一直没法实现。想知道重定向时怎么同时传递数据。
现有代码:
服务器端 Action 代码
'use server' import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation' import { createClient } from 'utils/supabase/server' export async function login() { const supabase = await createClient() const { data, error } = await supabase.auth.signInAnonymously() if (error) { redirect('/anonlogin'); } else { revalidatePath('/', 'layout') redirect('/') } }
登录页面组件代码
import { login } from '@/anonlogin/actions' import styles from '@/components/global/button.module.css' export default function LoginPage() { return ( <div> <form> <button className={styles.button} formAction={login}>Log in</button> </form> </div> ) }
可行解决方案
方案1:URL查询参数传错误信息
这是最直接简单的办法,把错误信息编码后拼到URL里,页面加载时读取显示。
修改服务器端 Action
'use server' import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation' import { createClient } from 'utils/supabase/server' export async function login() { const supabase = await createClient() const { data, error } = await supabase.auth.signInAnonymously() if (error) { // 编码错误信息避免特殊字符干扰 const encodedError = encodeURIComponent(error.message) redirect(`/anonlogin?error=${encodedError}`); } else { revalidatePath('/', 'layout') redirect('/') } }
修改登录页面组件读取参数
在App Router里,页面组件可以直接接收searchParams props来获取URL参数:
import { login } from '@/anonlogin/actions' import styles from '@/components/global/button.module.css' export default function LoginPage({ searchParams }) { // 解码并获取错误信息 const loginError = searchParams.error ? decodeURIComponent(searchParams.error) : null return ( <div> {/* 显示错误提示 */} {loginError && ( <div style={{ color: '#dc2626', marginBottom: '16px', padding: '8px', border: '1px solid #fecdd3', borderRadius: '4px' }}> {loginError} </div> )} <form> <button className={styles.button} formAction={login}>Log in</button> </form> </div> ) }
方案2:用Cookie临时存储错误信息
如果不想在URL里暴露错误内容,就用Cookie临时存,页面加载后读取再删掉。
修改服务器端 Action
'use server' import { revalidatePath } from 'next/cache' import { redirect } from 'next/navigation' import { createClient } from 'utils/supabase/server' import { cookies } from 'next/headers' export async function login() { const supabase = await createClient() const cookieStore = cookies() const { data, error } = await supabase.auth.signInAnonymously() if (error) { // 设置有效期1分钟的临时Cookie,只在当前路由生效 cookieStore.set('login_error', encodeURIComponent(error.message), { maxAge: 60, path: '/anonlogin', httpOnly: false, // 允许前端读取 secure: process.env.NODE_ENV === 'production' }) redirect('/anonlogin'); } else { revalidatePath('/', 'layout') redirect('/') } }
修改登录页面组件读取Cookie
需要改成客户端组件才能操作浏览器Cookie:
'use client' import { login } from '@/anonlogin/actions' import styles from '@/components/global/button.module.css' import { useEffect, useState } from 'react' export default function LoginPage() { const [loginError, setLoginError] = useState(null) useEffect(() => { // 从Cookie中提取错误信息 const errorCookie = document.cookie.split('; ') .find(row => row.startsWith('login_error=')) ?.split('=')[1] if (errorCookie) { const decodedError = decodeURIComponent(errorCookie) setLoginError(decodedError) // 读取后立即删除Cookie,避免重复显示 document.cookie = 'login_error=; path=/anonlogin; max-age=0' } }, []) return ( <div> {loginError && ( <div style={{ color: '#dc2626', marginBottom: '16px', padding: '8px', border: '1px solid #fecdd3', borderRadius: '4px' }}> {loginError} </div> )} <form> <button className={styles.button} formAction={login}>Log in</button> </form> </div> ) }
内容的提问来源于stack exchange,提问作者Shane Harley
相关产品推荐
相关产品推荐

