PAYATHON 2026

uniapp调用支付宝支付提示62001用户取消的原因

支付小周

结论

在 uni-app 中,62001 表示支付流程被取消,但不一定是用户主动点击了“取消”,也不能据此判断 order_str 的签名或参数有问题。

支付宝参数自查通过后,可以重点检查以下情况:

  1. orderInfo 传给 uni.requestPayment 前经过了解析、编码或重新拼接,最终字符串与服务端生成的内容不一致。
  2. 支付按钮被重复触发,多个支付请求互相覆盖。
  3. App 的支付宝支付模块、包名、Bundle ID、应用签名与支付宝开放平台中的应用配置不一致。
  4. 支付宝客户端未正常拉起,或者支付完成后无法正确回跳 App。
  5. 用户关闭了收银台、切换了应用,或支付流程被系统中断。
  6. 前端收到了“取消”回调,但订单实际上已经支付成功。

排查时不能只看 62001。还需要确认支付宝收银台是否拉起、失败发生在哪个阶段,并以服务端查询到的订单状态为准。

先确认 orderInfo 的传递方式

支付宝 App 支付使用的 orderInfo 应是服务端生成的完整签名字符串。前端收到后直接传入即可,不要将其转换为对象,也不要再次调用 encodeURIComponent、decodeURIComponent 或自行拼接。

uni.requestPayment({
  provider: 'alipay',
  orderInfo: orderStr,
  success(res) {
    console.log('支付宝支付回调成功:', res)
  },
  fail(err) {
    console.error('支付宝支付回调失败:', JSON.stringify(err))
  }
})

以下处理方式都可能破坏签名:

// 不要把 order_str 解析成对象后重新拼接
const params = parseOrderString(orderStr)

// 不要对完整 order_str 再次编码
const encoded = encodeURIComponent(orderStr)

// 不要把字符串包装成额外对象传入
uni.requestPayment({
  provider: 'alipay',
  orderInfo: {
    orderStr
  }
})

尤其要检查字符串中的 +、%、&、=、引号和空格。通过某些表单或 URL 参数传递时,或者解码方式不正确时,+ 可能会变成空格,导致传入 SDK 的内容与服务端生成的内容不同。

建议分别记录:

  • 服务端完成签名后的 order_str
  • App 从接口响应中收到的原始字符串
  • 调用 uni.requestPayment 前的字符串

比较三者的长度和内容,确认字符串没有被修改。如果日志包含签名等敏感数据,只能用于受控调试,不要上传到公开平台。

判断错误发生在哪个阶段

62001 出现在不同阶段,排查方向也不同。

支付宝收银台完全没有拉起

先检查 App 的集成配置:

  • manifest.json 是否勾选了支付宝支付模块。
  • 修改配置后,当前安装包是否重新云打包,或者重新制作了自定义基座。
  • Android 包名和应用签名是否与支付宝开放平台登记的信息一致。
  • iOS 的 Bundle ID、URL Scheme 等回跳配置是否正确。
  • 当前支付宝应用是否已经开通 App 支付能力,应用环境与订单环境是否一致。
  • 真机是否安装了能够正常运行的支付宝客户端。
  • 是否混用了正式环境和沙箱环境。

如果只在 HBuilderX 中修改模块配置,却继续使用修改前的基座或安装包,新的配置不会自动进入旧包,需要重新打包后再验证。

收银台拉起后立即关闭或返回

需要检查:

  • order_str 是否是本次请求新生成的订单。
  • 商户订单号是否被重复使用。
  • 订单是否已经关闭、超时或完成支付。
  • 服务端创建订单时使用的 app_id、私钥和支付宝公钥是否属于同一个开放平台应用。
  • product_code 等 App 支付业务参数是否正确。
  • 拉起支付后,代码是否立即跳转页面、关闭页面或退出 WebView。

参数自查工具通常只能检查订单参数和签名结构,不能证明运行时的 App 配置、包签名、支付权限及回跳链路都没有问题。

收银台正常显示,关闭后提示 62001

这通常表示用户关闭了收银台,或者支付过程被系统中断。前端可以按“支付未完成”处理,但不要立即将服务端订单标记为失败。此时订单可能仍在处理中,也可能已经支付成功。

用户已经付款,但 App 仍提示取消

遇到这种情况,应重点检查回跳和订单状态确认:

  • App 是否能从支付宝正常返回。
  • 是否重复调用了 uni.requestPayment。
  • 页面恢复时是否再次发起了支付。
  • 是否将前一次请求的失败回调当成了当前订单的结果。
  • 服务端是否收到支付宝异步通知。
  • 调用支付宝订单查询接口后,订单是否已经成功。

客户端回调不能作为最终支付凭证。只要客户端结果与实际情况不一致,就应由服务端查询订单状态。

防止重复拉起支付

按钮连续点击、生命周期重复执行或接口重复返回,都可能同时发起多个支付请求。可以增加支付锁:

let paying = false

async function payWithAlipay() {
  if (paying) {
    return
  }

  paying = true

  try {
    const orderStr = await createOrder()

    if (typeof orderStr !== 'string' || !orderStr.trim()) {
      throw new Error('服务端未返回有效的 orderInfo')
    }

    await new Promise((resolve, reject) => {
      uni.requestPayment({
        provider: 'alipay',
        orderInfo: orderStr,
        success: resolve,
        fail: reject
      })
    })

    // 不直接以前端回调作为入账依据
    await confirmOrderStatus()
  } catch (err) {
    console.error('支付宝支付未完成:', err)

    // 取消或未知结果时仍查询服务端订单状态
    await confirmOrderStatus()
  } finally {
    paying = false
  }
}

还要检查 onShow、按钮点击事件和请求重试逻辑,确认其中没有重复发起支付的代码。

正确处理支付结果

支付流程可以按以下方式处理:

  1. App 请求业务服务端创建订单。
  2. 服务端调用支付宝接口并完成签名。
  3. 服务端将原始 order_str 返回给 App。
  4. App 通过 uni.requestPayment 拉起支付宝。
  5. 无论前端返回成功、失败还是取消,都向业务服务端查询订单状态。
  6. 服务端根据支付宝异步通知或 alipay.trade.query 的查询结果更新订单。
  7. App 只展示服务端确认后的结果。

前端可以这样处理:

uni.requestPayment({
  provider: 'alipay',
  orderInfo: orderStr,
  async success() {
    const order = await queryBusinessOrder(orderNo)
    showOrderResult(order)
  },
  async fail(err) {
    console.warn('客户端支付回调:', err)

    const order = await queryBusinessOrder(orderNo)

    if (order.status === 'PAID') {
      uni.showToast({
        title: '支付成功',
        icon: 'success'
      })
    } else {
      uni.showToast({
        title: '支付未完成',
        icon: 'none'
      })
    }
  }
})

queryBusinessOrder 应查询业务服务端。App 不能持有支付宝私钥,也不能直接使用私钥调用支付宝接口。

建议的排查顺序

  1. 建立一个最简单的测试页面,只保留一次 uni.requestPayment 调用。
  2. 确认 orderInfo 是字符串,并逐字符比对,确保它与服务端生成的原始内容完全一致。
  3. 记录完整的 fail 回调对象,不要只截取 errMsg。
  4. 观察支付宝收银台是否成功拉起,并判断错误发生在拉起前、收银台内还是回跳后。
  5. 使用全新的商户订单号测试,避免重复订单造成干扰。
  6. 核对支付宝开放平台中的 app_id、App 支付能力、Android 包名与签名,以及 iOS Bundle ID 和回跳配置。
  7. 修改 manifest.json 或原生支付配置后,重新打包并安装。
  8. 换一台真机、另一个支付宝账号和稳定的网络进行交叉验证。
  9. 调用服务端订单查询接口,确认真实的交易状态。
  10. 如果仍无法定位,整理 App 平台、uni-app/HBuilderX 版本、打包方式、完整错误对象及支付宝 SDK 返回信息,再提交给 DCloud 或支付宝技术支持。

注意事项

  • 不要因为收到 62001 就直接关闭业务订单。
  • 不要只根据 success 回调发货或开通权益。
  • 支付宝私钥必须保存在服务端,不能写入 uni-app 前端代码。
  • 不要公开完整的 order_str,其中可能含有商户信息、订单信息和签名。
  • Android 和 iOS 需要分别测试,因为两端的包标识、签名及回跳机制不同。
  • 如果自定义基座可以支付,而正式包不能,重点比较两者的包名、签名和模块配置。
  • 如果正式包可以支付,而自定义基座不能,通常也与基座配置或签名不符合支付宝平台登记信息有关。

参数自查通过后,应优先确认传入 SDK 的字符串是否保持原样、支付是否被重复拉起、安装包的身份配置是否匹配,以及服务端查询到的真实订单状态。

备注:内容仅供参考。