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

Stripe支付成功后如何向数据库添加订单数据?

解决支付成功后添加订单到数据库的问题

核心思路

不能依赖前端跳转后的请求写入订单(存在篡改、跳过风险),必须通过Stripe Webhooks监听支付成功事件,在后端安全完成订单创建与数据库写入操作。

具体实现步骤

1. 配置Stripe Webhook端点

在Stripe后台的「开发者工具 -> Webhooks」中,添加你的后端Webhook地址(例如https://your-domain.com/payment/webhook),订阅checkout.session.completed事件(该事件会在用户支付成功后触发)。复制Stripe提供的签名密钥,存入NestJS环境变量(如STRIPE_WEBHOOK_SECRET)。

2. 在NestJS中添加Webhook控制器与处理逻辑

修改payment.controller.ts,新增Webhook接收接口:

import { Controller, Post, Body, Headers } from '@nestjs/common';
import { Stripe } from 'stripe';
import { PaymentService } from './payment.service';

@Controller('payment')
export class PaymentController {
  private stripe: Stripe;

  constructor(
    private paymentService: PaymentService,
  ) {
    this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
      apiVersion: '2024-06-20', // 使用当前Stripe最新API版本
    });
  }

  // 原有创建支付会话接口
  @Post()
  async createPayment(@Body() data: CartItem[]) {
    return this.paymentService.processPayment(data);
  }

  // 新增Webhook处理接口
  @Post('webhook')
  async handleWebhook(
    @Body() rawBody: Buffer,
    @Headers('stripe-signature') signature: string,
  ) {
    let event: Stripe.Event;
    try {
      // 验证请求签名,确保来自Stripe
      event = this.stripe.webhooks.constructEvent(
        rawBody,
        signature,
        process.env.STRIPE_WEBHOOK_SECRET,
      );
    } catch (err) {
      console.log('Webhook签名验证失败', err.message);
      return { status: 'error', message: err.message };
    }

    // 处理支付成功事件
    if (event.type === 'checkout.session.completed') {
      const session = event.data.object as Stripe.Checkout.Session;
      await this.paymentService.createOrderFromSession(session);
    }

    return { status: 'success' };
  }
}

3. 优化支付会话创建,添加元数据(可选但推荐)

在创建Stripe会话时,通过metadata字段存储自定义数据(如用户ID、购物车标识),方便后续Webhook处理时关联订单:
修改payment.service.ts的createSession方法:

async createSession(processedCartItems: ProcessedCartItem[], userId?: string) {
  return this.stripe.checkout.sessions.create({
    line_items: processedCartItems.map(item => ({
      price_data: {
        currency: 'usd',
        unit_amount: item.price * 100,
        product_data: {
          name: item.name,
          images: ['https://material.angular.io/assets/img/examples/shiba1.jpg']
        },
      },
      quantity: item.quantity,
    })),
    mode: 'payment',
    success_url: process.env.STRIPE_SUCCESS_URL,
    cancel_url: process.env.STRIPE_CANCEL_URL,
    // 添加元数据存储自定义信息
    metadata: {
      userId: userId || 'guest', // 登录用户传ID,游客用默认值
      // 可添加cartId等标识,方便关联前端购物车数据
    },
  });
}

4. 实现订单写入数据库的服务方法

在payment.service.ts中新增createOrderFromSession方法,解析Stripe会话数据并写入数据库:

async createOrderFromSession(session: Stripe.Checkout.Session) {
  // 1. 解析会话数据
  const userId = session.metadata?.userId;
  const lineItems = await this.stripe.checkout.sessions.listLineItems(session.id);
  
  // 2. 构造订单数据结构
  const orderData = {
    userId,
    stripeSessionId: session.id,
    totalAmount: session.amount_total / 100, // Stripe返回金额为分,转成元
    status: 'paid',
    items: lineItems.data.map(item => ({
      productName: item.description,
      quantity: item.quantity,
      price: item.amount_subtotal / 100,
    })),
    // 若需收货地址等信息,可从session.shipping等字段提取
  };

  // 3. 写入数据库(替换为你的订单Repository操作)
  // await this.orderRepository.save(orderData);
  console.log('订单已创建并写入数据库:', orderData);
}

5. 前端注意事项

  • 无需在success_url页面额外发送订单创建请求,Webhook已完成后端处理
  • 若需在成功页展示订单信息,可通过前端API查询(例如用Stripe会话ID作为参数)

关键注意点

  • 必须做签名验证:防止伪造请求,确保仅处理Stripe官方发送的事件
  • 禁止依赖前端触发订单创建:用户可能直接访问成功页,Webhook是唯一可靠的支付成功通知渠道
  • 保证幂等性:Stripe可能重试Webhook请求,需通过stripeSessionId等唯一标识避免重复创建订单

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 09:28:09