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

Stripe checkout.session.completed Webhook异常:支付成功但订单未创建

订单未创建及票券不显示问题排查

一、订单未创建的核心原因

1. createOrder函数异常被吞且日志无效

createOrder中console.log("order created")写在return语句之后,永远不会执行,无法确认订单是否创建成功。同时如果handleError仅打印错误而不重新抛出,会导致数据库保存失败时无任何报错反馈,webhook仍返回200,Stripe认为处理成功但实际订单未写入。

修复:

export const createOrder = async (order: CreateOrderParams) => {
  try {
    await connectToDatabase();
    
    console.log("creating order");
    const newOrder = await Order.create({
      ...order,
      event: order.eventId,
      buyer: order.buyerId,
    });

    console.log("order created"); // 移至return前
    return JSON.parse(JSON.stringify(newOrder));
  } catch (error) {
    handleError(error);
    throw error; // 重新抛出异常,让上层捕获
  }
};

2. ObjectId类型不匹配

从Stripe metadata获取的eventId和buyerId是字符串,而Mongoose模型中event和buyer字段应为ObjectId类型,直接传入字符串会导致数据库保存失败(若模型开启严格类型校验)。

修复:

import { ObjectId } from "mongodb";

export const createOrder = async (order: CreateOrderParams) => {
  try {
    await connectToDatabase();
    
    console.log("creating order");
    const newOrder = await Order.create({
      ...order,
      event: new ObjectId(order.eventId), // 转换为ObjectId
      buyer: new ObjectId(order.buyerId), // 转换为ObjectId
    });

    console.log("order created");
    return JSON.parse(JSON.stringify(newOrder));
  } catch (error) {
    handleError(error);
    throw error;
  }
};

3. Webhook未捕获createOrder异常

当前webhook未对createOrder的调用做异常捕获,若创建失败会直接返回500,但如果handleError吞了异常,会导致Stripe误以为处理成功。

修复webhook代码:

if (eventType === "checkout.session.completed") {
  const { id, amount_total, metadata } = event.data.object;

  const order = {
    stripeId: id,
    eventId: metadata?.eventId || "",
    buyerId: metadata?.buyerId || "",
    totalAmount: amount_total ? (amount_total / 100).toString() : "0",
    createdAt: new Date(),
  };

  try {
    const newOrder = await createOrder(order);
    return NextResponse.json({ message: "OK", order: newOrder });
  } catch (err) {
    console.error("Failed to create order:", err);
    return NextResponse.json({ message: "Failed to create order", error: err }, { status: 500 });
  }
}

二、票券未显示的额外问题

即使订单创建成功,getOrdersByUser函数存在语法错误,导致无法正确查询用户订单:

1. Order.distinct("event._id").find(...)调用错误

distinct方法返回数组,无法链式调用find、sort等查询方法,会导致查询失败返回空数据。

修复:

export async function getOrdersByUser({
  userId,
  limit = 3,
  page,
}: GetOrdersByUserParams) {
  try {
    await connectToDatabase();

    const skipAmount = (Number(page) - 1) * limit;
    const conditions = { buyer: new ObjectId(userId) }; // 转换为ObjectId

    const orders = await Order.find(conditions)
      .sort({ createdAt: "desc" })
      .skip(skipAmount)
      .limit(limit)
      .populate({
        path: "event",
        model: Event,
        populate: {
          path: "organizer",
          model: User,
          select: "_id firstName lastName",
        },
      });

    const ordersCount = await Order.countDocuments(conditions);

    return {
      data: JSON.parse(JSON.stringify(orders)),
      totalPages: Math.ceil(ordersCount / limit),
    };
  } catch (error) {
    handleError(error);
    throw error;
  }
}

三、额外排查步骤

  • 确认MongoDB连接正常,检查connectToDatabase函数无错误;
  • 在Stripe Dashboard查看checkout.session.completed事件的请求体,确认metadata中eventId和buyerId是否正确传递;
  • 查看服务器日志(如Vercel/Netlify日志),检查createOrder的日志是否执行,是否有数据库错误信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:55:56