PAYATHON 2026

uniapp 线上调用支付宝支付报 62009 未知错误

支付小周

结论

62009 是 uni-app/5+ 支付模块调用支付宝 SDK 失败时返回的通用错误,仅凭这个编号无法锁定具体原因。线上环境出现该错误,问题通常不在 uni.requestPayment 的业务逻辑,而在以下环节:

  • 线上安装包的包名、Bundle ID 或应用签名与支付宝开放平台的配置不一致;
  • 线上包未正确包含支付宝支付模块;
  • 服务端生成的 orderInfo 被前端再次编码、解码或拼接,导致 RSA2 验签失败;
  • app_id、应用私钥和支付宝公钥来自不同应用或不同环境;
  • 支付宝开放平台的 App 支付能力尚未开通或生效;
  • 订单已经过期,或者设备时间与服务端时间相差过大。

问题中的订单参数包含 timestamp=2022-11-02 16:29:44 和 time_expire=2022-11-02 16:59:44。如果继续使用这组固定参数测试,订单一定已经过期,无法用于当前排查。请让服务端重新生成订单。

先检查线上包配置

如果测试包可以支付,正式线上包却无法调起支付宝,先检查应用身份配置。

Android

以下信息必须完全一致:

  • uni-app 项目的 Android 包名;
  • 正式 APK/AAB 的实际包名;
  • 支付宝开放平台配置的应用包名;
  • 支付宝开放平台登记的应用签名;
  • 正式打包时实际使用的签名证书。

调试包和正式包经常使用不同的签名证书。即使包名相同,证书不同也会产生不同的应用签名。

可以从实际安装包中读取签名信息并进行比对,例如:

apksigner verify --print-certs app-release.apk

如果使用 AAB,还要检查最终由应用商店发布并安装到设备上的 APK,不能只看本地构建配置。

iOS

检查以下内容:

  • Bundle ID 是否与支付宝开放平台登记的值一致;
  • 正式包使用的 App ID、描述文件和签名证书是否正确;
  • 云打包时是否勾选并配置了支付宝支付模块;
  • App Store、企业签名或 Ad Hoc 包是否使用了预期的 Bundle ID。

修改支付模块或原生配置后,需要重新制作自定义基座或重新云打包。只更新前端资源不会改变原生支付模块。

检查支付宝开放平台配置

确认订单中的参数:

app_id=2021001199623389
method=alipay.trade.app.pay
product_code=QUICK_MSECURITY_PAY
sign_type=RSA2

这些参数要与服务端当前配置一致,同时检查:

  1. app_id 对应的支付宝应用是否已经上线,或是否处于允许当前调用方式的状态;
  2. App 支付产品是否已经签约并生效;
  3. 服务端使用的应用私钥是否属于该 app_id;
  4. 验签使用的支付宝公钥是否来自同一个应用;
  5. 是否混用了沙箱和正式环境的应用、密钥或网关;
  6. 修改应用公钥后,服务端是否仍在使用旧私钥签名。

还要分清“应用公钥”和“支付宝公钥”:

  • 应用私钥:商户服务端用它为订单签名;
  • 应用公钥:需要上传到支付宝开放平台;
  • 支付宝公钥:商户服务端用它验证支付宝回调签名。

由服务端直接生成完整订单字符串

支付宝 App 支付应在服务端完成签名。前端只接收完整的订单字符串,然后原样传给 uni.requestPayment。

Java 服务端可以使用支付宝 SDK 生成订单字符串:

AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipay.com/gateway.do",
    appId,
    appPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl("https://example.com/api/payment/alipay/notify");

AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(outTradeNo);
model.setTotalAmount("1.01");
model.setSubject("普通商品");
model.setProductCode("QUICK_MSECURITY_PAY");

request.setBizModel(model);

AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderInfo = response.getBody();

把 response.getBody() 直接返回给 App。不要将参数拆成 JSON,也不要在前端重新排序或生成签名。

金额建议使用字符串或 BigDecimal,以免出现浮点数精度问题:

model.setTotalAmount(new BigDecimal("1.01").toPlainString());

uni-app 调用方式

前端拿到服务端返回的 orderInfo 后,直接调用:

uni.requestPayment({
  provider: 'alipay',
  orderInfo: orderInfo,
  success(res) {
    console.log('支付宝客户端返回:', res)

    // 客户端 success 不代表最终到账。
    // 应继续请求服务端查询订单支付状态。
  },
  fail(err) {
    console.error('支付调用失败:', JSON.stringify(err))
    console.error('errCode:', err.errCode)
    console.error('errMsg:', err.errMsg)
    console.error('rawdata:', err.rawdata)
  }
})

不要再次对完整订单字符串执行:

encodeURIComponent(orderInfo)

也不要随意执行:

decodeURIComponent(orderInfo)

支付宝 SDK 需要服务端签名后生成的原始字符串。再次编码、调整参数顺序、替换空格或修改大小写,都可能改变参与签名的内容。

下面这种写法容易出错:

// 不推荐
orderInfo: encodeURIComponent(orderInfo)

应直接传递服务端返回的内容:

// 正确:原样传递服务端结果
orderInfo: orderInfo

检查接口传输过程是否修改了加号

RSA2 签名经常包含 +、/、= 等字符。如果订单字符串经过表单解析、URL 查询参数或错误的解码流程,+ 可能会被转换成空格,最终导致验签失败。

建议服务端通过 JSON 字段返回订单:

{
  "code": 0,
  "data": {
    "orderInfo": "alipay_sdk=...&app_id=...&sign=..."
  }
}

前端读取 JSON 字段后直接使用:

const orderInfo = response.data.data.orderInfo

不要把订单字符串作为未正确编码的 URL 查询参数传输,例如:

/pay?orderInfo=alipay_sdk=...&sign=...

排查时,可以在服务端生成订单后记录它的哈希值,再由客户端对收到的内容计算相同的哈希值。两端结果不一致,说明字符串在传输过程中被修改了。日志中不要长期保留完整签名、用户信息或其他敏感支付数据。

获取支付宝 SDK 的实际返回信息

62009 只是外层错误。失败对象中的 rawdata、resultStatus 或支付宝客户端日志通常包含更有用的信息。

常见的支付宝状态包括:

  • 9000:订单支付成功;
  • 6001:用户取消;
  • 6002:网络连接异常;
  • 4000:订单支付失败;
  • 8000:结果确认中。

具体状态仍要以当前支付宝 SDK 的返回值和服务端订单查询结果为准。不能只根据客户端回调判断支付成功,最终结果应以支付宝异步通知的验签结果或服务端主动查询结果为准。

建议完整打印失败对象:

fail(err) {
  console.error('alipay payment error:', JSON.stringify(err, null, 2))

  let rawdata = err.rawdata

  if (typeof rawdata === 'string') {
    try {
      rawdata = JSON.parse(rawdata)
    } catch (e) {
      // rawdata 不一定是 JSON,保留原始字符串
    }
  }

  console.error('alipay rawdata:', rawdata)
}

如果日志中只有 62009,完全没有支付宝的 resultStatus,重点检查原生支付模块、正式包签名和支付宝应用身份配置。如果已经拿到 resultStatus,再根据该状态检查订单参数、签名或网络问题。

排查顺序

  1. 让服务端重新生成一笔未过期的新订单,不要继续使用示例中的历史参数。
  2. 确认正式安装包包含支付宝支付模块。
  3. 核对线上包的实际包名、Bundle ID 和应用签名。
  4. 核对支付宝开放平台登记的包名和签名。
  5. 确认 App 支付产品已经签约并生效。
  6. 核对 app_id、应用私钥和支付宝公钥是否属于同一个正式应用。
  7. 对比服务端生成的 orderInfo 和客户端收到的内容,确认两者完全一致。
  8. 确认前端没有再次编码、解码、排序或拼接订单参数。
  9. 输出完整的失败对象,重点检查 rawdata 和 resultStatus。
  10. 由服务端调用支付宝订单查询接口,确认支付宝是否已经接收或创建该订单。

如果本地调试正常,只有正式包失败,先检查正式包签名和原生模块配置。如果所有环境都失败,先检查服务端签名、密钥匹配、订单字符串传输和 App 支付签约状态。

备注:内容仅供参考。