Next.js Clerk <SignIn/>组件配置错误及auth-callback实现求助
问题:Clerk
组件配置错误及auth-callback实现方案return (<SignIn/>)
一、问题背景
使用Next.js、Next.js Actions、Clerk和Prisma开发时,遇到Clerk的<SignIn/>组件配置错误,按错误提示处理后未解决,需获取错误修复方案及auth-callback的正确实现方式。
二、控制台错误信息
Uncaught (in promise) Error:
Clerk: Thecomponent is not configured correctly. The most likely reasons for this error are:return (<SignIn/>)
- "/olustur/onizleme"路由不是兜底路由。建议将该路由转换为兜底路由,例如:"/olustur/onizleme/[[...rest]]/page.tsx"。或者,你可以通过将“routing”属性设置为“hash”,更新
组件以使用基于哈希的路由。return (<SignIn/>)return (<SignIn/>组件挂载在兜底路由中,但“/olustur/onizleme”下的所有路由都被中间件保护。要解决此问题,请确保中间件不保护兜底路由或其子路由。如果你使用“createRouteMatcher”工具,可以考虑在路由模式末尾添加“(.*)”,例如:"/olustur/onizleme(.*)"。 )
三、相关代码
LoginModal.jsx
import { X } from "lucide-react" import { SignIn } from "@clerk/nextjs" export default function LoginModal({ isOpen, setIsOpen }) { return ( <div className={`w-full h-full flex items-center justify-center fixed inset-0 z-[999] bg-[#000] bg-opacity-35 overflow-hidden ${isOpen ? 'flex' : 'hidden'}`}> <div className="relative"> <SignIn /> <X className="absolute top-4 z-10 right-4 w-4 h-4 cursor-pointer" onClick={() => setIsOpen(false)} /> </div> </div> ) }
app/auth-callback/page.jsx
'use client' import { Loader2 } from "lucide-react" import { useRouter } from "next/navigation" import { useEffect, useState } from "react" import { useQuery } from "@tanstack/react-query" import { getAuthStatus } from "./_actions/actions" export default function Page() { const router = useRouter() const [configId, setConfigId] = useState(null) useEffect(() => { const configurationId = localStorage.getItem('configurationId') if(configurationId) { setConfigId(configurationId) } }, []) const { data } = useQuery({ queryKey: ['auth-callback'], queryFn: async() => await getAuthStatus(), retry: true, retryDelay: 500, }) console.log(data) if(data?.success) { if(configId) { localStorage.removeItem('configurationId') router.push(`/olustur/onizleme?id=${configId}`) } else { router.push('/') } } return ( <div className="w-full h-[94vh] flex items-center justify-center text-center"> <div className="gap-0.5 flex flex-col items-center"> <Loader2 className="w-8 h-8 animate-spin text-[#4e4e53]" /> <h2 className="text-xl font-semibold">Giris yapildi..</h2> <p className="text-sm">Otomatik olarak yonledirileceksiniz..</p> </div> </div> ) }
app/auth-callback/_actions/actions.js
'use server' import { db } from '@/app/db' import { currentUser } from '@clerk/nextjs/server' export const getAuthStatus = async() => { const user = await currentUser() console.log(user) try { if (!user?.id || !user.emailAddresses[0].emailAddress) { throw new Error('Gecersiz kullanici bilgileri!') } const existingUser = await db.user.findFirst({ where: { id: user.id }, }) if (!existingUser) { await db.user.create({ data: { id: user.id, email: user.emailAddresses[0].emailAddress, }, }) } return { success: true } } catch (error) { console.log('Error:', error) return { success: false } } }
四、错误解决方法
方案1:给return (<SignIn/>)
添加哈希路由配置
return (<SignIn/>)无需修改路由结构,直接给组件添加routing="hash"属性,让Clerk用哈希片段处理跳转逻辑:
<SignIn routing="hash" />
方案2:将目标路由改为兜底路由
把/olustur/onizleme的路由结构调整为兜底路由:
- 原路径:
app/olustur/onizleme/page.tsx - 修改后:
app/olustur/onizleme/[[...rest]]/page.tsx
该路由会匹配所有/olustur/onizleme下的子路径,满足Clerk的路由要求。
方案3:调整中间件路由保护规则
检查Clerk中间件(通常为middleware.ts),确保/olustur/onizleme及其子路由不被强制保护:
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server' const isProtectedRoute = createRouteMatcher([ '/dashboard(.*)', '!/olustur/onizleme(.*)' // 排除目标路由及子路径 ]) export default clerkMiddleware((auth, req) => { if (isProtectedRoute(req)) auth().protect() }) export const config = { matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'], }
五、auth-callback优化实现
1. 替换localStorage为路由参数传递
避免依赖localStorage,通过redirectUrl传递configId:
// 打开LoginModal时传入redirectUrl <LoginModal isOpen={isOpen} setIsOpen={setIsOpen} redirectUrl={`/auth-callback?configId=${configId}`} /> // 修改LoginModal中的SignIn组件 <SignIn routing="hash" redirectUrl={redirectUrl} />
在auth-callback页面用useSearchParams获取参数:
'use client' import { useSearchParams } from 'next/navigation' export default function Page() { const router = useRouter() const searchParams = useSearchParams() const configId = searchParams.get('configId') // 移除原localStorage相关逻辑 }
2. 完善加载与错误状态处理
添加加载、错误状态的UI展示,避免空白或异常:
const { data, isLoading, error } = useQuery({ queryKey: ['auth-callback'], queryFn: async() => await getAuthStatus(), retry: 3, retryDelay: 500, }) if (isLoading) { return ( <div className="w-full h-[94vh] flex items-center justify-center text-center"> <div className="gap-0.5 flex flex-col items-center"> <Loader2 className="w-8 h-8 animate-spin text-[#4e4e53]" /> <h2 className="text-xl font-semibold">Giris yapildi..</h2> <p className="text-sm">Otomatik olarak yonledirileceksiniz..</p> </div> </div> ) } if (error || !data?.success) { return ( <div className="w-full h-[94vh] flex items-center justify-center text-center"> <h2 className="text-xl font-semibold text-red-500">Giris basarisiz!</h2> <button onClick={() => router.push('/')} className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"> Ana sayfaya don </button> </div> ) } // 成功后跳转 useEffect(() => { router.push(configId ? `/olustur/onizleme?id=${configId}` : '/') }, [router, configId]) return null
3. 服务端逻辑原子化优化
用Prisma的upsert替代findFirst+create,避免并发创建用户的问题:
'use server' import { db } from '@/app/db' import { currentUser } from '@clerk/nextjs/server' export const getAuthStatus = async() => { const user = await currentUser() try { if (!user?.id || !user.emailAddresses[0]?.emailAddress) { throw new Error('Gecersiz kullanici bilgileri!') } await db.user.upsert({ where: { id: user.id }, update: { email: user.emailAddresses[0].emailAddress }, create: { id: user.id, email: user.emailAddresses[0].emailAddress, }, }) return { success: true } } catch (error) { console.error('Auth status error:', error) return { success: false, error: error.message } } }
内容的提问来源于stack exchange,提问作者Ahmet
相关产品推荐
相关产品推荐

