我正在尝试将我的 Clerk 数据同步到我的 Next js 13 项目中的数据库。我的 webhooks 通过 Ngrok 公开暴露。这是我的代码:
import { IncomingHttpHeaders } from "http";
import { headers } from "next/headers";
import { NextResponse } from "next/server";
import { Webhook, WebhookRequiredHeaders } from "svix";
const webhookSecret = process.env.WEBHOOK_SECRET || "";
async function handler(request: Request) {
console.log(await request.json())
const payload = await request.json();
const headersList = headers();
const heads = {
"svix-id": headersList.get("svix-id"),
"svix-timestamp": headersList.get("svix-timestamp"),
"svix-signature": headersList.get("svix-signature"),
};
const wh = new Webhook(webhookSecret);
let evt: Event | null = null;
try {
evt = wh.verify(
JSON.stringify(payload),
heads as IncomingHttpHeaders & WebhookRequiredHeaders
) as Event;
} catch (err) {
console.error((err as Error).message);
return NextResponse.json({}, { status: 400 });
}
const eventType: EventType = evt.type;
if (eventType === "user.created" || eventType === "user.updated") {
const { id, ...attributes } = evt.data;
console.log(attributes)
}
}
type EventType = "user.created" | "user.updated" | "*";
type Event = {
data: Record<string, string | number>;
object: "event";
type: EventType;
};
export const GET = handler;
export const POST = handler;
export const PUT = handler;
此代码应执行以下操作:
/api/webhooks/user
但是,据我所知,只有步骤 1 有效。在我的职员仪表板中,我收到错误:
{
"message": "src property must be a valid json object"
}
使用以下代码我仍然遇到相同的错误:
import { Webhook, WebhookRequiredHeaders } from "svix";
const webhookSecret = process.env.WEBHOOK_SECRET || "";
async function handler(request: Request) {
const svix_id = request.headers.get("svix-id") ?? "";
const svix_timestamp = request.headers.get("svix-timestamp") ?? "";
const svix_signature = request.headers.get("svix-signature") ?? "";
const body = await request.text(); // This get's the raw body as a string
const sivx = new Webhook("your_secret_key_here");
const payload = sivx.verify(body, {
"svix-id": svix_id,
"svix-timestamp": svix_timestamp,
"svix-signature": svix_signature,
});
console.log(payload)
}
export const GET = handler;
export const POST = handler;
export const PUT = handler;
我哪里出错了?
您需要将 webhook 端点添加到 middleware.ts 中的忽略路由中:
export default authMiddleware({
publicRoutes: ['/'],
ignoredRoutes: ['/api/{routeName}'],
});
然而,令人烦恼的是,很少有文档来强调这一点。
对于使用 Hono 的人,我使用以下代码使其工作。
app.post('/', async (c) => {
try {
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET
if (!WEBHOOK_SECRET) {
throw new Error('You need a WEBHOOK_SECRET in your .env')
}
const payload = await c.req.text()
const svix_id = c.req.header('svix-id')
const svix_timestamp = c.req.header('svix-timestamp')
const svix_signature = c.req.header('svix-signature')
// If there are no Svix headers, error out
if (!svix_id || !svix_timestamp || !svix_signature) {
console.error('Issue in headers of webhook')
return c.text('Error occurred -- no svix headers', {
status: 400,
})
}
// Create a new Svix instance with your secret.
const wh = new Webhook(WEBHOOK_SECRET)
let evt = null
// Attempt to verify the incoming webhook
// If successful, the payload will be available from 'evt'
// If the verification fails, error out and return error code
try {
evt = wh.verify(payload, {
'svix-id': svix_id,
'svix-timestamp': svix_timestamp,
'svix-signature': svix_signature,
}) as { data: OrganizationMembershipJSON; type: string }
console.log('evt type: ', evt.type)
console.log('evt data: ', evt.data?.id)
} catch (err) {
if (err instanceof Error) {
console.error('Error verifying webhook:', err.message)
return c.text(err.message, 400)
}
return c.text('Something went wrong', 500)
}
return c.text('Webhook received and verified successfully', 200)
} catch (e) {
if (e instanceof Error) {
return c.json(e.message, 400)
}
return c.text('Something went wrong', 500)
}
})