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

Next.js 13 App目录下获取Stripe Webhook原始请求体遇阻

解决Next.js中Stripe Webhook原始请求体获取问题

你遇到的核心问题在于:

  • 开启bodyParser: true时,Next.js会自动解析请求体为JSON对象,破坏了Stripe签名验证所需的原始未加工字节流,导致"invalid body"错误
  • 关闭bodyParser后,请求是原生的可读流,若buffer函数实现不当或未正确处理请求头,会出现"content-type is undefined"错误

正确实现方案

以下是适配Next.js(App Router)的完整代码,包含原始请求体读取、content-type校验和Stripe签名验证:

import { NextResponse } from 'next/server';
import Stripe from 'stripe';

// 必须禁用bodyParser,保留原始请求体
export const config = {
  api: {
    bodyParser: false,
  },
};

// 自定义函数读取请求流为Buffer
async function buffer(req: Request) {
  const chunks: Uint8Array[] = [];
  for await (const chunk of req.body!) {
    chunks.push(chunk);
  }
  return Buffer.concat(chunks);
}

export async function POST(request: Request) {
  try {
    // 手动获取content-type请求头
    const contentType = request.headers.get('content-type');
    if (!contentType || !contentType.includes('application/json')) {
      return NextResponse.json({ error: '无效的内容类型' }, { status: 400 });
    }

    // 读取原始请求体
    const rawBody = await buffer(request);

    // Stripe签名验证(必须步骤)
    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
      apiVersion: '2024-06-20', // 替换为你的Stripe API版本
    });
    const signature = request.headers.get('stripe-signature');
    const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;

    let event: Stripe.Event;
    try {
      event = stripe.webhooks.constructEvent(
        rawBody,
        signature!,
        webhookSecret
      );
    } catch (err) {
      console.error('Stripe签名验证失败:', err);
      return NextResponse.json({ error: '无效签名' }, { status: 400 });
    }

    // 处理具体Stripe事件示例
    switch (event.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = event.data.object as Stripe.PaymentIntent;
        console.log('支付成功:', paymentIntent.id);
        // 此处添加你的业务逻辑
        break;
      default:
        console.log(`未处理的事件类型: ${event.type}`);
    }

    return NextResponse.json({ status: 200 });
  } catch (err) {
    console.error('请求处理失败:', err);
    return NextResponse.json({ error: '服务器内部错误' }, { status: 500 });
  }
}

关键说明

  1. 禁用bodyParser:这是Stripe Webhook的硬性要求,只有原始字节流才能通过签名验证
  2. 正确读取请求流:在Next.js App Router中,request.body是ReadableStream,需用for await...of循环读取所有chunk并拼接为Buffer
  3. 手动校验content-type:关闭bodyParser后Next.js不会自动解析请求头,需手动获取并验证是否为Stripe发送的application/json类型
  4. 签名验证不可省略:即使你暂时只需要原始体,也必须保留签名验证步骤,避免恶意请求

内容的提问来源于stack exchange,提问作者strmzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 13:32:35