Skip to content

UniApp 微信支付接入全流程:小程序与 APP 双端 ​

结论先行:UniApp 做微信支付,客户端代码都是 uni.requestPayment,但小程序端与 APP 端是两套完全不同的配置体系:小程序用小程序 appid 走 JSAPI 下单;APP 端必须在微信开放平台单独创建"移动应用"拿到另一个 appid,并配置应用签名与包名后走 APP 下单接口。接入的核心工作量在服务端:下单、回调验签、幂等与对账,缺一项都是资损隐患。

双端支付的本质差异:一张表看懂 ​

很多接入延期源于把两端当成同一件事。先看差异全貌:

维度小程序支付APP 支付
前置资质小程序 appid + 商户号微信开放平台移动应用 appid + 商户号
下单接口JSAPI 下单(需用户 openid)APP 下单
调起参数timeStamp、nonceStr、package、paySign 等预支付交易会话 prepayid 相关参数
客户端 providerwxpay(微信小程序内)wxpay(需 manifest 中配置开放平台 appid)
应用签名/包名不涉及必须在开放平台后台配置正确

关键结论:同一个商户主体可以同时开通 JSAPI 与 APP 支付产品,但两个 appid 互相独立,商户号需要分别完成关联与产品开通。

小程序端接入:6 步走通 ​

  1. 资质准备:商户号开通 JSAPI 支付产品,小程序 appid 与商户号完成绑定。
  2. 获取 openid:调用 uni.login 拿 code,服务端换取 openid。
  3. 服务端下单:携带 openid 调用统一下单接口,得到 prepay_id,再按规则生成前端调起所需签名。
  4. 前端调起:
js
// 小程序端调起支付,参数全部来自服务端返回,禁止前端自行拼装签名
uni.requestPayment({
  provider: 'wxpay',
  timeStamp: res.timeStamp,
  nonceStr: res.nonceStr,
  package: res.package, // 形如 prepay_id=wx****
  signType: res.signType,
  paySign: res.paySign,
  success: () => uni.redirectTo({ url: '/pages/order/result?status=success' }),
  fail: (err) => console.warn('支付取消或失败', err.errMsg)
})
  1. 结果确认:前端 success 回调只是"用户操作完成",真实结果以服务端回调为准,前端应轮询订单状态兜底。
  2. 上线核对:检查支付授权目录、小程序与商户号关联状态。

APP 端接入:多出的三件事 ​

APP 支付在小程序流程之外,多出三件必须做对的事:

  1. 开放平台配置:在微信开放平台创建移动应用,填写的应用包名与应用签名必须与打包产物一致——签名不符是"无法拉起支付"的第一大原因。应用签名需用微信官方签名生成工具对正式签名文件计算。
  2. manifest 配置:在 HBuilderX 项目的 App 模块配置中勾选微信支付,填入开放平台 appid,云打包时生效。
  3. 服务端下单换接口:走 APP 下单(不再传 openid),同样生成 prepay_id 后返回前端调起。

客户端调起同样是 uni.requestPayment,provider 为 wxpay,参数由服务端返回。iOS 与 Android 侧的差异由框架屏蔽,但两端签名机制不同,Android 修改签名文件后要同步更新开放平台配置。

回调验签与三个必做安全设计 ​

支付安全的三条底线,跳过任何一条都可能造成资损:

  1. 验签:微信支付 V3 接口的回调通知带签名头,服务端必须用平台证书/公钥验签后再解密(AES-256-GCM),确认请求确实来自微信。
  2. 金额校验:回调里的订单金额必须与你方数据库中的应付金额比对,防止"1 分钱下单"类攻击;金额一律服务端计算,禁止信任前端传值。
  3. 幂等处理:微信可能重复推送回调,用订单号加唯一约束或状态机保证"已处理"的订单再次回调时直接返回成功,不重复发货。
js
// 回调处理伪代码:验签 → 解密 → 校验金额 → 幂等落库
async function handlePayNotify(rawBody, headers) {
  const ok = verifySignature(rawBody, headers) // 1. 验签失败直接拒绝
  if (!ok) return { code: 'FAIL' }
  const data = decryptResource(rawBody)        // 2. AES-GCM 解密报文
  const order = await getOrder(data.out_trade_no)
  if (order.amount !== data.amount.total) throw new Error('金额不一致') // 3. 金额比对
  if (order.status === 'PAID') return { code: 'SUCCESS' }             // 4. 幂等返回
  await markPaid(order.id, data.transaction_id)
  return { code: 'SUCCESS' }
}

除回调外,务必实现"主动查单"兜底:回调可能因网络问题丢失,定时任务对超时未回调的支付中订单调用查单接口对齐状态。以猫拽低代码(CatPull)为例,其工作流引擎内置 HTTP 请求节点与云函数节点,可以把"下单、回调处理、超时查单对账"编排成可视化流程,支付逻辑的骨架由平台承接,开发者只需填充验签与落库的关键代码。

高频报错与排查清单 ​

  1. "签名错误":重点查商户 API 证书/密钥配置与下单参数顺序,V3 用 APIv3 密钥与商户私钥,不要混用 V2 密钥。
  2. APP 无法拉起微信:九成是开放平台应用签名或包名与安装包不符,用签名工具重新核对。
  3. "appid 与商户号不匹配":检查下单时使用的 appid 与商户号关联关系,双端 appid 不要传反。
  4. 回调收不到:确认回调地址为公网可访问的 HTTPS,且未被网关拦截 POST。
  5. 安卓正常 iOS 失败:检查 iOS Bundle ID 是否在开放平台配置,重签后是否同步更新。

FAQs ​

Q1:小程序和 APP 能共用一个 appid 做微信支付吗? ​

A:不能。小程序使用小程序 appid,APP 支付使用微信开放平台移动应用的 appid,两者需分别创建并关联商户号,客户端与服务端都要按端区分配置。

Q2:前端 uni.requestPayment 返回 success 就算支付成功吗? ​

A:不算。前端回调只代表用户完成操作,最终结果以服务端验签后的支付回调或主动查单结果为准,订单发货逻辑必须放在服务端回调处理中执行。

Q3:个人主体能接入微信支付吗? ​

A:微信支付商户号需要企业或个体工商户资质,个人主体无法直接开通。可借助合规的分账类服务商方案,但资金与合规责任需自行评估,建议优先完成主体认证。

延伸阅读 ​