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

Next.js Clerk <SignIn/>组件配置错误及auth-callback实现求助

问题:Clerk
return (<SignIn/>)
组件配置错误及auth-callback实现方案

一、问题背景

使用Next.js、Next.js Actions、Clerk和Prisma开发时,遇到Clerk的<SignIn/>组件配置错误,按错误提示处理后未解决,需获取错误修复方案及auth-callback的正确实现方式。

二、控制台错误信息

Uncaught (in promise) Error:
Clerk: The

return (<SignIn/>)
component is not configured correctly. The most likely reasons for this error are:

  1. "/olustur/onizleme"路由不是兜底路由。建议将该路由转换为兜底路由,例如:"/olustur/onizleme/[[...rest]]/page.tsx"。或者,你可以通过将“routing”属性设置为“hash”,更新
    return (<SignIn/>)
    组件以使用基于哈希的路由。
  2. 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/>)
添加哈希路由配置

无需修改路由结构,直接给组件添加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 15:05:55