支付是商业类小程序的核心能力。小程序支付以平台支付为底层,通过 统一下单调起支付支付回调 三段式完成。本文梳理完整对接流程,并强调金额、幂等与验签这些最容易出问题的地方。

一、开通前置条件

对接支付前需要满足:

  • 小程序主体为企业/个体工商户(个人主体不支持支付)
  • 完成支付商户号开通与结算账户绑定
  • 在开放平台后台配置支付目录、回调地址等参数
  • 申请对应的商户密钥(API 密钥 / APIv3 密钥)
个人主体小程序无法开通支付,需要先升级主体或使用第三方支付通道,这是很多个人开发者第一个遇到的硬门槛。

二、统一下单

后端收到下单请求后,携带金额与订单号调用平台统一下单接口:

// Node.js 统一下单示例(简化)
const params = {
  appid: APP_ID,
  mch_id: MCH_ID,
  description: '商品购买',
  out_trade_no: orderNo,       // 商户订单号,必须唯一
  amount: { total: 1000 },     // 单位:分
  notify_url: NOTIFY_URL,      // 支付结果回调地址
  payer: { openid: userOpenid },
};

// 签名后发送请求
const prepayRes = await requestPaymentOrder(params);
// 返回 prepay_id

几个关键点:

  • 金额单位是分:以整数(分)传递,避免浮点数精度问题
  • out_trade_no 唯一:商户订单号,全局唯一,重复会导致下单失败
  • openid 从登录态获取:支付必须绑定发起支付的小程序用户

三、前端调起支付

统一下单成功拿到 prepay_id 后,后端按规范签名生成支付参数,返回给前端调起支付:

// 小程序端
wx.requestPayment({
  timeStamp: payData.timeStamp,
  nonceStr: payData.nonceStr,
  package: 'prepay_id=' + payData.prepayId,
  signType: 'RSA',
  paySign: payData.paySign,
  success() {
    // 支付成功(最终以回调为准)
  },
  fail() {
    // 用户取消或支付失败
  },
});
前端 success 只代表用户完成了支付确认,业务结果必须以服务端回调为准。

四、支付回调与验签

支付完成后平台会向 notify_url 异步推送结果。回调处理是支付对接的核心:

// 回调验签(以 APIv3 为例)
const { createVerify, createPublicKey } = require('crypto');

function verifyNotify(headers, body, platformPubKey) {
  const msg = headers['wechatpay-timestamp'] + '\n'
    + headers['wechatpay-nonce'] + '\n'
    + body + '\n';
  const signature = headers['wechatpay-signature'];
  const verify = createVerify('RSA-SHA256');
  verify.update(msg);
  verify.end();
  return verify.verify(createPublicKey(platformPubKey), signature, 'base64');
}

回调处理的完整姿势:

  1. 验签:用平台公钥验证签名,验签失败直接拒绝
  2. 解密:回调报文是密文,用 APIv3 密钥解密
  3. 幂等处理:同一个订单可能收到多次回调,处理前检查订单状态
  4. 更新业务:校验金额与订单一致后更新订单状态、发发货
  5. 应答:返回成功应答,通知平台停止重试

五、退款与对账

退款同样通过 API 完成,注意:

  • 退款金额不能超过原支付金额
  • 退款也需要回调通知,同样要验签与幂等
  • 定期拉取账单(T+1),与本地订单对账,及时发现差异

六、安全与常见坑

  • 验签不过:检查是否用错了证书/密钥版本,时间戳过期需同步服务器时间
  • 重复发货:回调重试导致重复发货,务必按订单状态加锁判断
  • 金额校验:回调中的金额必须与下单金额一致,防止篡改
  • 密钥保管:商户密钥只能存在服务端,绝不能出现在小程序代码中
  • 回调地址安全:回调接口不做业务鉴权,但必须验签,防止伪造回调

小结

支付对接的成败在于细节:金额以分为单位、回调必须验签、业务处理必须幂等。把这三点做到位,再配合对账机制,支付链路就能稳定可靠。