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

使用paypal-checkout-server-sdk处理PayPal交易成功后的后续操作方案

PayPal支付回调服务端处理改造方案

核心逻辑是移除客户端的订单捕获操作,将支付结果校验、礼品发放等核心业务全部放到服务端执行,彻底避免前端篡改风险。


1. 修改客户端代码

删除原onApprove回调中的actions.order.capture()逻辑,改为将用户授权通过的订单ID提交到服务端,由服务端完成后续捕获和校验:

paypal.Buttons({
    createOrder: function () {
        return fetch('/create-order', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                items: [{
                    id: 2,
                    quantity: 1
                }],
            })
        }).then((res) => {
            if (res.ok) return res.json()
            return res.json().then(json => Promise.reject(json))
        }).then(({ id }) => {
            return id
        }).catch((err) => {
            console.error(err)
        })
    },
    onApprove: function (data, actions) {
        // 移除客户端捕获逻辑,把订单ID传给服务端处理
        return fetch('/capture-order', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                orderId: data.orderID
            })
        }).then((res) => {
            if (res.ok) return res.json()
            return res.json().then(json => Promise.reject(json))
        }).then((res) => {
            if (res.success) {
                alert('捐赠成功,您的礼品将会尽快发放')
                // 这里可以加跳转到礼品领取页的逻辑
            } else {
                alert('支付失败,请重试:' + res.msg)
            }
        }).catch((err) => {
            console.error(err)
            alert('支付处理异常')
        })
    },
}).render("#paypal")

2. 服务端新增订单捕获接口

新增/capture-order接口,调用PayPal官方SDK完成订单捕获,同时做多层安全校验,校验通过后再执行礼品发放逻辑:

// 原有storeItems、/、/create-order接口逻辑保持不变

app.post('/capture-order', async (req, res) => {
    const { orderId } = req.body
    const captureRequest = new paypal.orders.OrdersCaptureRequest(orderId)
    captureRequest.prefer('return=representation')

    try {
        const capture = await paypalClient.execute(captureRequest)
        const orderResult = capture.result

        // 第一层校验:支付状态必须为完成
        if (orderResult.status !== 'COMPLETED') {
            return res.status(400).json({ success: false, msg: '支付未完成' })
        }

        // 第二层校验:实付金额、商品信息和创建订单时匹配
        const purchaseUnit = orderResult.purchase_units[0]
        const payAmount = parseInt(purchaseUnit.amount.value)
        const itemId = parseInt(purchaseUnit.items[0].name.match(/\d+/)[0]) // 从商品名称提取捐赠档位ID
        const expectedAmount = storeItems.get(itemId).price

        if (payAmount !== expectedAmount) {
            return res.status(400).json({ success: false, msg: '支付金额不匹配' })
        }

        // 校验全部通过,执行业务逻辑:记录捐赠记录、给用户发放礼品
        // 这里写你自己的业务代码,比如更新用户权益、生成领取码等
        // ========== 业务逻辑 start ==========
        // 示例:db.donationRecords.insert({ userId: xxx, amount: payAmount, itemId: itemId, orderId: orderId })
        // ========== 业务逻辑 end ==========

        res.json({ success: true, msg: '支付成功' })
    } catch (err) {
        res.status(500).json({ success: false, msg: err.message })
        console.error('订单捕获失败:', err.message)
    }
})

额外安全注意事项

  • 可以在创建订单时把订单ID和对应用户、商品档位的关系存在本地数据库,捕获时直接查询本地记录校验,不需要从PayPal返回的商品信息解析,更安全
  • 增加幂等判断:处理业务逻辑前先查本地数据库有没有该orderId的成功记录,避免重复处理导致重复发礼品
  • 不要信任客户端传递的任何金额、商品档位参数,所有数值都以服务端存储和PayPal返回的结果为准

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:54:06