使用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
相关产品推荐
相关产品推荐

