如何在 Next.js 中处理 Stripe 和 Paystack Webhook(App Router 方式)
Source: Dev.to
为什么 webhook 签名验证经常失败
开发者在 SaaS 支付中最头疼的第一件事就是 Webhook 签名验证。
你已经把一切配置好,测试付款也成功了,但服务器返回 400 Bad Request 或 Signature Verification Failed 错误。
在 Next .js App Router 中,问题通常出在请求体的解析方式。Stripe 和 Paystack 需要 原始请求体 来验证签名,但 Next .js 往往会在你获取原始负载之前先把它解析为 JSON。
处理 Stripe 和 Paystack webhook 的黄金模式(2026)
在 app/api/webhooks/route.ts 下创建文件。在 App Router 中可以使用 req.text() 获取原始正文,避免自动解析。
import { NextResponse } from "next/server";
import crypto from "crypto";
export async function POST(req: Request) {
// 1️⃣ 获取原始正文文本
const body = await req.text();
// 2️⃣ 从请求头中获取签名
const signature =
req.headers.get("x-paystack-signature") ||
req.headers.get("stripe-signature");
if (!signature) {
return NextResponse.json(
{ error: "No signature" },
{ status: 400 }
);
}
// 3️⃣ 验证签名(Paystack 示例)
const hash = crypto
.createHmac("sha512", process.env.PAYSTACK_SECRET_KEY!)
.update(body)
.digest("hex");
if (hash !== signature) {
return NextResponse.json(
{ error: "Invalid signature" },
{ status: 401 }
);
}
// 4️⃣ 解析正文并处理事件
const event = JSON.parse(body);
if (event.event === "charge.success") {
// 在数据库中处理成功支付
console.log(
"Payment successful for:",
event.data.customer.email
);
}
return NextResponse.json(
{ received: true },
{ status: 200 }
);
}
中间件注意事项
如果你有全局中间件保护路由,请 排除 webhook 路径。否则,支付提供商可能会被重定向到登录页,导致请求无法到达你的 API。
webhook 失败会怎样?
当 webhook 验证失败时,用户将得不到 “Pro” 权限,导致流失率上升。正确的处理方式是把副业项目和真正业务之间的关键区别。
进一步阅读
- 完整实现(包括 Stripe、Paystack 以及数据库逻辑):How to add Stripe or Paystack payments to your SaaS
- SassyPack 概览(为创始人解决 “Day 1” 技术痛点):SassyPack
祝编码愉快!