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

Node.js中集成PayPal与Stripe支付的最优实现方案是什么

Node.js电商项目同时集成Stripe与PayPal支付方案

前置准备

  • 注册两个平台的开发者账号,获取对应环境的密钥:Stripe的STRIPE_SECRET_KEY、STRIPE_PUBLISHABLE_KEY、STRIPE_WEBHOOK_SECRET,PayPal的PAYPAL_CLIENT_ID、PAYPAL_CLIENT_SECRET,注意区分沙箱和生产环境密钥,不要混用
  • 项目中安装官方SDK:npm install stripe @paypal/checkout-server-sdk

后端核心逻辑实现(以Express框架为例)

初始化客户端

// 初始化Stripe客户端
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
// 初始化PayPal客户端
const paypal = require('@paypal/checkout-server-sdk');
const environment = process.env.NODE_ENV === 'production' 
  ? new paypal.core.LiveEnvironment(process.env.PAYPAL_CLIENT_ID, process.env.PAYPAL_CLIENT_SECRET)
  : new paypal.core.SandboxEnvironment(process.env.PAYPAL_CLIENT_ID, process.env.PAYPAL_CLIENT_SECRET);
const paypalClient = new paypal.core.PayPalHttpClient(environment);

通用订单预处理逻辑

不管用户选择哪种支付方式,先在自有系统内创建待支付订单,记录订单ID、对应金额、商品信息、用户ID,订单状态标记为待支付,同时做好订单金额校验,避免前端传参篡改支付金额。

Stripe支付相关接口

// 创建Stripe支付会话接口
app.post('/api/payment/stripe/create', async (req, res) => {
  const { orderId } = req.body;
  // 查询自有数据库订单信息,校验订单状态、金额合法性
  const order = await Order.findById(orderId);
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [
      {
        price_data: {
          currency: 'cny',
          product_data: { name: `订单${orderId}` },
          unit_amount: order.amount * 100, // Stripe金额单位为分,需做单位转换
        },
        quantity: 1,
      }
    ],
    mode: 'payment',
    success_url: `${process.env.FRONTEND_URL}/payment/success?orderId=${orderId}`,
    cancel_url: `${process.env.FRONTEND_URL}/payment/cancel?orderId=${orderId}`,
    metadata: { orderId: orderId }
  });
  res.json({ sessionId: session.id, jumpUrl: session.url });
});

// Stripe webhook回调接口,用于可靠更新订单状态
app.post('/api/payment/stripe/webhook', express.raw({type: 'application/json'}), async (req, res) => {
  const sig = req.headers['stripe-signature'];
  const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
  if (event.type === 'checkout.session.completed') {
    const orderId = event.data.object.metadata.orderId;
    // 更新订单状态为已支付,触发后续发货、通知逻辑
    await Order.findByIdAndUpdate(orderId, { status: 'paid', paymentMethod: 'stripe' });
  }
  res.json({ received: true });
});

PayPal支付相关接口

// 创建PayPal支付订单接口
app.post('/api/payment/paypal/create', async (req, res) => {
  const { orderId } = req.body;
  const order = await Order.findById(orderId);
  const request = new paypal.orders.OrdersCreateRequest();
  request.prefer("return=representation");
  request.requestBody({
    intent: 'CAPTURE',
    purchase_units: [{
      reference_id: orderId,
      amount: { currency_code: 'CNY', value: order.amount.toString() }
    }],
    application_context: {
      return_url: `${process.env.FRONTEND_URL}/payment/success?orderId=${orderId}`,
      cancel_url: `${process.env.FRONTEND_URL}/payment/cancel?orderId=${orderId}`,
    }
  });
  const paypalOrder = await paypalClient.execute(request);
  const approvalUrl = paypalOrder.result.links.find(link => link.rel === 'approve').href;
  res.json({ paypalOrderId: paypalOrder.result.id, jumpUrl: approvalUrl });
});

// PayPal支付捕获接口
app.post('/api/payment/paypal/capture', async (req, res) => {
  const { paypalOrderId, orderId } = req.body;
  const request = new paypal.orders.OrdersCaptureRequest(paypalOrderId);
  request.requestBody({});
  const captureResult = await paypalClient.execute(request);
  if (captureResult.result.status === 'COMPLETED') {
    // 更新订单状态为已支付
    await Order.findByIdAndUpdate(orderId, { status: 'paid', paymentMethod: 'paypal' });
    res.json({ success: true });
  } else {
    res.json({ success: false, msg: '支付未完成' });
  }
});

前端对接逻辑

  • 支付页提供两个支付选项按钮,用户选择Stripe时调用/api/payment/stripe/create接口,拿到跳转链接后直接跳转至Stripe支付页即可
  • 用户选择PayPal时,调用/api/payment/paypal/create接口,拿到跳转链接后跳转至PayPal支付页,用户支付完成回跳前端成功页时,再调用/api/payment/paypal/capture接口完成最终的订单状态更新

注意事项

  • 所有密钥全部存放在环境变量中,严禁硬编码到代码仓库
  • 订单支付状态更新必须以服务端回调/接口校验结果为准,不能信任前端回跳携带的支付成功参数
  • 开发阶段统一使用两个平台的沙箱环境测试,流程全量跑通后再切换生产密钥
  • 建议增加定时任务轮询超时未支付的订单状态,避免回调丢失导致订单状态异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 13:36:03