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

Next.js服务端组件结合Clerk+Hono鉴权无法获取数据求助

Next.js服务端组件+Clerk+Hono.js认证问题排查

我使用Next.js服务端组件,搭配Clerk认证包、Hono.js后端(Drizzle ORM),通过搜索参数获取数据时遇到核心问题:服务端组件无法传递Clerk认证会话或令牌,导致后端返回未授权,无法正常获取数据。

测试验证情况:

  • 移除后端的clerkMiddleware和用户ID校验后,能正常获取数据
  • 将服务端组件打印的令牌拿到Postman中请求,能成功返回数据,但服务端组件内的请求始终失败

服务端组件代码

import { UserNav } from "@/components/data-table/user-nav";
import { searchParamsSchema } from "@/db/validations";
import { client } from "@/lib/hono";
import TaskUi from "@/view/tasks/TaskUi";
import { auth } from "@clerk/nextjs/server";

type Props = {
    searchParams: Record<string, string>;
};

export const revalidate = 0;

export default async function TaskPage({ searchParams }: Props) {
    const search = searchParamsSchema.parse(searchParams);
    const { getToken } = auth();

    const token = await getToken();
    console.log("🚀 ~ TaskPage ~ token:", token);
    const response = await client.api.tasks.$get({
        query: search,
        headers: { Authorization: `Bearer ${token}` },
    });

    console.log("🚀 ~ response headers:", response.headers);

    if (!response.ok) {
        throw new Error("Error fetching tasks");
    }

    const initialData = await response.json();

    return (
        <>
            <div className="h-full flex-1 flex-col space-y-8 p-8 md:flex">
                <div className="flex items-center justify-between space-y-2">
                    <div>
                        <h2 className="text-2xl font-bold tracking-tight">Welcome back!</h2>
                        <p className="text-muted-foreground">Here&apos;s a list of your tasks for this month!</p>
                    </div>
                    <div className="flex items-center space-x-2">
                        <UserNav />
                    </div>
                </div>
                <TaskUi initialData={initialData} search={search} />
            </div>
        </>
    );
}

终端日志

🚀 ~ response headers: Headers {
  'x-clerk-auth-reason': 'dev-browser-missing',
  'x-clerk-auth-status': 'signed-out',
  'x-middleware-rewrite': '/api/tasks?page=1&per_page=10',
  'content-type': 'application/json; charset=UTF-8',
  date: 'Wed, 02 Oct 2024 06:46:45 GMT',
  connection: 'keep-alive',
  'keep-alive': 'timeout=5',
  'transfer-encoding': 'chunked'
}

后端Hono.js代码

const app = new Hono()
    .use("*", clerkMiddleware())
    .get("/", async (ctx) => {
        const query = ctx.req.query();
        const parsedParams = getTasksSchema.safeParse(query);
        const auth = getAuth(ctx);

        if (!auth?.userId) {
            return ctx.json({ error: "Unauthorized" }, 401);
        }

        if (!parsedParams.success) {
            return ctx.json({ error: "Invalid query params" }, 400);
        }

// 省略业务逻辑代码

        return ctx.json({
            data,
            meta: {
                page,
                pageCount,
                total,
            },
        });
    })

报错信息

⨯ Error: Error fetching tasks
    at TaskPage (D:\Workspace\2. Projects\company-website\.next\server\chunks\ssr\_935b95._.js:1232:15)
digest: "3934253529"
 ⨯ Error: Error fetching tasks
    at TaskPage (D:\Workspace\2. Projects\company-website\.next\server\chunks\ssr\_935b95._.js:1232:15)
digest: "3934253529"

排查与解决方案

1. 检查getToken参数配置

Clerk的getToken()默认生成Clerk JWT,但Hono的clerkMiddleware可能需要指定正确的JWT受众或模板。尝试显式配置:

// 使用自定义JWT模板(需在Clerk Dashboard提前配置)
const token = await getToken({ template: 'your-task-api-template' });
// 或指定受众
const token = await getToken({ audience: process.env.NEXT_PUBLIC_API_URL });

2. 确认服务端组件的认证上下文

先打印完整的auth()结果,验证用户会话是否存在:

const authResult = auth();
console.log("🚀 ~ TaskPage ~ authResult:", authResult);
// 若未认证,直接重定向到登录页
if (!authResult.userId) {
  redirect('/sign-in');
}

如果userId不存在,说明服务端组件未获取到会话,可能是:

  • Next.js路由中间件未正确配置Clerk保护逻辑
  • 开发环境下Clerk Cookie无法被服务端正确读取

3. 修正Hono后端的Clerk中间件配置

确保Hono的clerkMiddleware配置了正确的密钥和域:

import { clerkMiddleware, getAuth } from '@hono/clerk-auth';

const app = new Hono()
  .use('*', clerkMiddleware({
    secretKey: process.env.CLERK_SECRET_KEY,
    publishableKey: process.env.CLERK_PUBLISHABLE_KEY,
    domain: process.env.CLERK_DOMAIN,
  }))

同时添加CORS配置,允许前端请求携带凭证:

import { cors } from 'hono/cors';

app.use('*', cors({
  origin: process.env.NEXT_PUBLIC_APP_URL,
  credentials: true,
}));

4. 依赖Cookie传递会话(同域场景)

若前后端同域,可去掉手动设置的Authorization头,让请求自动携带Clerk会话Cookie:

const response = await client.api.tasks.$get({
  query: search,
  credentials: 'include', // 确保携带Cookie
});

5. 开发环境特殊处理

针对日志中的dev-browser-missing提示,可尝试:

  • 确认浏览器已登录Clerk账户且会话有效
  • 重启Next.js开发服务器,清除浏览器缓存和Cookie
  • 检查Clerk Dashboard的会话有效期配置

内容的提问来源于stack exchange,提问作者Md. Mahadad Hossain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:42:03