NextJS14接收Stripe CLI的POST请求正常,但无法处理Webhook
问题:Stripe Webhook事件触发但处理逻辑未执行
已确认通过Stripe CLI发送的Webhook POST请求能被正常接收,checkout.session.completed事件也已触发,但Webhook的处理逻辑(包括控制台日志输出、Supabase数据插入等操作)均未执行。以下是./api/webhook/route.ts的代码:
./api/webhook/route.ts import { createClient } from '@supabase/supabase-js'; import { headers } from 'next/headers'; import { NextRequest, NextResponse } from 'next/server'; import { NextApiRequest, NextApiResponse } from 'next'; import Stripe from 'stripe'; import { Resend } from 'resend'; import EmailTemplate from '@/components/email-template'; const resend = new Resend(process.env.NEXT_RESEND_API_KEY); const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ); const stripe = new Stripe(`${process.env.STRIPE_SECRET_KEY}`, { apiVersion: '2023-08-16', }); //Handling incoming POST req async function POST(request: NextRequest) { try { const body = await request.text(); const endpointSecret = process.env.STRIPE_SECRET_WEBHOOK_KEY!; const sig = headers().get('stripe-signature') as string; // const sig = headers().get('Stripe-Signature') as string; let event: Stripe.Event; //read the event data from stripe try { event = stripe.webhooks.constructEvent(body, sig, endpointSecret); } catch (err) { return new Response(`Webhook Error: ${err}`, { status: 400, }); } console.log(`Received event !webhook!: ${event?.type}`); // Handle the event: checkout.session.completed switch (event.type) { case 'checkout.session.completed': const session: any = event.data.object; console.log('!Checkout session completed!:', session.payment_status); // get customer name, email const customerEmail = session.customer_details.email; const customerName = session.customer_details.name; // create the customer in db const { data: customer, error: errorCustomer } = await supabase .from('Customer') .insert({ customerName, customerEmail }) .select() .single(); if (errorCustomer) throw new Error(errorCustomer.message); break; default: } return NextResponse.json({ received: true }); } catch (error) { return NextResponse.json({ error }, { status: 400 }); } } async function GET(request: NextApiRequest, response: NextApiResponse) { // Bad Request or how ever you want to respond. return response.status(400).json({ error: 'Bad Request' }); } export { POST, GET };
排查关键点:
- 签名验证失败:Stripe发送的签名头是
Stripe-Signature(首字母大写),当前代码使用小写的stripe-signature获取,会导致签名验证失败,直接进入catch返回400,后续逻辑无法执行。建议启用注释里的正确写法。 - 环境变量配置问题:确认
STRIPE_SECRET_WEBHOOK_KEY、STRIPE_SECRET_KEY等环境变量是否在运行环境中正确加载,Next.js中环境变量需要确保在服务器端可访问。 - Supabase权限不足:当前使用的
NEXT_PUBLIC_SUPABASE_ANON_KEY是前端匿名密钥,权限有限,后端操作应使用SUPABASE_SERVICE_ROLE_KEY,否则插入数据会因权限失败,且被外层catch捕获后无日志输出。 - 日志查看方式错误:Next.js App Router的API路由日志属于服务器端日志,本地开发需查看终端输出,生产环境需查看对应平台的服务器日志,前端控制台无法看到这些日志。
- 事件类型匹配问题:确认Stripe发送的事件类型确实是
checkout.session.completed,可在Stripe Dashboard的Webhook事件详情中核对,避免拼写错误导致switch分支不触发。
内容的提问来源于stack exchange,提问作者Ehtz
相关产品推荐
相关产品推荐

