如何在 Next.js 中处理 Stripe 和 Paystack Webhook(App Router 方式)

发布: (2026年1月13日 GMT+8 12:01)
3 min read
原文: Dev.to

Source: Dev.to

为什么 webhook 签名验证经常失败

开发者在 SaaS 支付中最头疼的第一件事就是 Webhook 签名验证
你已经把一切配置好,测试付款也成功了,但服务器返回 400 Bad RequestSignature 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” 权限,导致流失率上升。正确的处理方式是把副业项目和真正业务之间的关键区别。

进一步阅读

祝编码愉快!

Back to Blog

相关文章

阅读更多 »