Next.JS认证回调页TRPCClientError:非有效JSON致无法跳转
解决Next.js认证回调页面的TRPCClientError:Unexpected token '<'错误
问题描述
在Next.js的src/app/auth-callback/page.tsx认证回调页面调用tRPC的authCallback接口时,触发以下错误:
TRPCClientError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
页面卡在加载状态,无法按预期跳转到仪表盘或登录页。
相关客户端页面代码:
'use client' import { useRouter, useSearchParams } from 'next/navigation' import { trpc } from '../_trpc/client' const Page = () => { const router = useRouter() const searchParams = useSearchParams() const origin = searchParams.get('origin') trpc.authCallback.useQuery(undefined, { onSuccess: ({ success }) => { if (success) { router.push(origin ? `/${origin}` : '/dashboard') } }, onError: err => { if (err.data?.code === 'UNAUTHORIZED') { router.push('/sign-in') } }, }) return ( <div> <div> <p>You will be redirected automatically.</p> </div> </div> ) } export default Page
对应的tRPC authCallback Procedure代码:
authCallback: publicProcedure.query(async () => { const { getUser } = getKindeServerSession() const user = getUser() console.log('auth user', user) if (!user.id || !user.email) throw new TRPCError({ code: 'UNAUTHORIZED' }) const dbUser = await db.user.findFirst({ where: { id: user.id, }, }) if (!dbUser) { await db.user.create({ data: { id: user.id, email: user.email, }, }) } return { success: true } }),
原因分析
这个错误的核心是tRPC客户端收到的不是预期的JSON响应,而是HTML内容。具体到这个场景:
getKindeServerSession()是服务器端专属方法,无法在客户端组件中正常执行,会触发服务器端错误,导致返回HTML错误页面而非JSON响应。- 客户端调用tRPC接口时,服务器返回的HTML被当作JSON解析,自然触发语法错误。
解决方案
将认证回调逻辑迁移到服务器组件中,直接使用Next.js的服务器端能力处理会话验证和跳转,无需通过tRPC:
修改src/app/auth-callback/page.tsx为服务器组件:
import { redirect } from 'next/navigation' import { db } from '@/db' // 替换为你的数据库导入路径 import { getKindeServerSession } from '@kinde-oss/kinde-auth-nextjs/server' const Page = async ({ searchParams }: { searchParams: { origin?: string } }) => { const { getUser } = getKindeServerSession() const user = getUser() // 验证用户会话,失败则跳转到登录页 if (!user.id || !user.email) { redirect('/sign-in') } // 检查并创建数据库用户 const dbUser = await db.user.findFirst({ where: { id: user.id }, }) if (!dbUser) { await db.user.create({ data: { id: user.id, email: user.email }, }) } // 跳转到目标页面 redirect(searchParams.origin ? `/${searchParams.origin}` : '/dashboard') } export default Page
为什么这样解决?
- 服务器组件可以直接调用Kinde的服务器端会话方法,确保正确获取用户信息,不会触发环境不兼容错误。
- 使用Next.js内置的
redirect方法直接完成跳转,避免了客户端到服务器的额外tRPC请求,流程更高效。 - 彻底规避了HTML响应被当作JSON解析的问题,从根源解决错误。
备选方案(保留tRPC)
如果一定要通过tRPC处理逻辑,需要确保authCallback Procedure在服务器端正确执行:
- 确保tRPC路由配置正确,
/api/trpc接口未被其他页面路由覆盖。 - 检查
publicProcedure是否允许执行服务器端逻辑,若需要会话验证,应使用带会话中间件的Procedure(比如protectedProcedure)。 - 避免在tRPC Procedure中调用只能在特定环境运行的方法,确保所有依赖的服务(如Kinde)能在tRPC的执行环境中正常工作。
内容的提问来源于stack exchange,提问作者dopez
相关产品推荐
相关产品推荐

