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

Next.js中Stripe webhook的constructEvent未定义问题求助

问题分析与解决方案

核心问题1:Stripe Webhook方法拼写错误

你的代码中调用了stripe.webhook.constructEvent,但Stripe Node.js SDK(v8及以上版本)中正确的方法名是复数形式的stripe.webhooks.constructEvent。单数的stripe.webhook不存在,因此会抛出Cannot read properties of undefined (reading 'constructEvent')错误。

核心问题2:变量作用域错误

payload和sig变量定义在if (req.method === "POST")的代码块内部,外部的try块无法访问这两个变量,即使修复了方法名,也会因为参数未定义导致验证失败。

修复后的完整代码

import { buffer } from "micro";
import * as admin from "firebase-admin";

const serviceAccount = require("../../../credentials.json");

const app = !admin.apps.length
  ? admin.initializeApp({
      credentials: admin.credential.cert(serviceAccount),
    })
  : admin.app();

// 初始化Stripe
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);

const endpointSecret = process.env.SIGNING_SECRET;

const fulfillOrder = async (session) => {
  console.log("Fill Order");
  return app
    .firestore()
    .collection("users")
    .doc(session.metadata.email)
    .collection("orders")
    .doc(session.id)
    .set({
      amount: session.amount_total / 100,
      amount_shipping: session.total_details.amount_shipping / 100,
      images: JSON.parse(session.metadata.images),
      timestamp: admin.firestore.FieldValue.serverTimestamp(),
    })
    .then(() => {
      console.log(`Success: Order ${session.id} added to db `);
    });
};

export default async (req, res) => {
  // 仅处理POST请求
  if (req.method !== "POST") {
    return res.status(405).send("Method Not Allowed");
  }

  const requestBuffer = await buffer(req);
  const payload = requestBuffer.toString();
  const sig = req.headers["stripe-signature"];

  let event;
  // 验证事件来源
  try {
    // 修正为复数形式的webhooks
    event = stripe.webhooks.constructEvent(payload, sig, endpointSecret);
  } catch (error) {
    console.log("Error", error.message);
    return res.status(400).send(`Webhook error: ${error.message}`);
  }

  // 处理结账完成事件
  if (event.type === "checkout.session.completed") {
    const session = event.data.object;
    return fulfillOrder(session)
      .then(() => res.status(200).send("Success")) // 补充响应内容
      .catch((error) =>
        res.status(400).send(`Webhook error: ${error.message}`)
      );
  }

  // 处理其他事件类型
  res.status(200).send("Received");
};

export const config = {
  api: {
    bodyParser: false,
    externalResolver: true,
  },
};

额外注意事项

  1. 环境变量验证:确保.env.local文件中正确配置了STRIPE_SECRET_KEY和SIGNING_SECRET,且Stripe CLI输出的签名密钥与SIGNING_SECRET一致。
  2. 字段修正:原代码中session.amount.total应为session.amount_total(Stripe Checkout Session的正确字段名),避免后续写入Firestore时出现错误。
  3. 响应完整性:所有分支都需要返回完整的HTTP响应(如res.status(200).send('Success')),避免请求超时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 18:55:31