PAYATHON 2026

支付宝 App 支付返回 6001 且无详细错误码

支付小周

结论

6001 不是 alipay.trade.app.pay 接口返回的业务错误码,而是支付宝客户端 SDK 返回的 resultStatus,表示“用户取消支付”。因此,这类结果通常不会附带 sub_code、sub_msg 等服务端错误信息。

不过,给出的 orderStr 还有两处需要修正或确认:

  1. biz_content 缺少 App 支付通常必需的 product_code: "QUICK_MSECURITY_PAY"。
  2. 传给客户端支付 SDK 的应该是签名后的参数串,通常不应带有 https://openapi.alipay.com/gateway.do? 前缀。建议使用 Node.js SDK 的 sdkExec() 生成,不要手工拼接网关地址。

仅凭这段 URL 无法判断 RSA2 签名是否正确。验签还需要签名前的原始字符串、应用公钥配置和对应的支付宝公钥。

为什么没有详细错误码

支付宝 App 支付有两类返回结果:

  • resultStatus:移动端支付 SDK 返回的状态,如 9000、6001、6002。
  • code、sub_code:支付宝开放平台接口返回的服务端业务结果。

常见的客户端状态如下:

resultStatus含义
9000支付成功
8000正在处理中
4000支付失败
6001用户取消支付
6002网络连接异常
6004支付结果未知,需要查询确认

用户在收银台返回、关闭支付页面或取消操作时,客户端可能直接返回 6001。交易此时未必已经进入会产生服务端业务错误的阶段,所以不会有更具体的 sub_code。

因此,6001 没有详细错误码属于正常情况。

orderStr 中需要检查的问题

1. 缺少 product_code

当前 biz_content 解码后为:

{
  "out_trade_no": "07E99000221227113937TFA8",
  "total_amount": 0.1,
  "subject": "购买商品"
}

建议改为:

{
  "out_trade_no": "07E99000221227113937TFA8",
  "total_amount": "0.10",
  "subject": "购买商品",
  "product_code": "QUICK_MSECURITY_PAY"
}

total_amount 建议使用保留两位小数的字符串,避免不同语言或序列化库处理浮点数时出现差异。

缺少业务参数通常会引发服务端参数错误,这类错误更可能返回 4000,而不是 6001。因此,这个问题需要修复,但不一定是本次出现 6001 的直接原因。

2. 不要把网关 URL 传给客户端 SDK

App 支付客户端需要的是类似下面的参数串:

app_id=...&biz_content=...&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=...&version=1.0&sign=...

不是:

https://openapi.alipay.com/gateway.do?method=...

网关地址用于服务端 HTTP API 请求。App 支付的 orderStr 应由服务端 SDK 的 sdkExec() 等方法生成,再原样传给 Android 或 iOS 支付 SDK。

如果当前代码在 sdkExec() 的结果前手工添加了网关地址,需要删除该前缀。

3. 无法通过编码后的 sign 判断签名是否正确

以下情况都可能导致签名失败:

  • 使用了错误应用的私钥。
  • app_id 与私钥所属应用不一致。
  • 开放平台配置的应用公钥与当前私钥不配对。
  • 将“支付宝公钥”误当作“应用公钥”上传。
  • 签名后又修改了 biz_content、金额或其他参数。
  • 参数被重复 URL 编码。
  • 客户端接收或传递 orderStr 时发生截断。
  • RSA2 实际使用的算法不是 SHA256WithRSA。
  • 私钥格式或换行处理不正确。

不要尝试通过手工调整参数顺序或编码方式来修复签名。参数排序、签名和 URL 编码应优先交给官方服务端 SDK 处理。

推荐的 Node.js 生成方式

以下示例展示了生成逻辑。具体导入方式需要与项目实际安装的 alipay-sdk-nodejs 版本一致:

const AlipaySdk = require('alipay-sdk').default;

const alipaySdk = new AlipaySdk({
  appId: '2021003126642283',
  privateKey: process.env.ALIPAY_APP_PRIVATE_KEY,
  alipayPublicKey: process.env.ALIPAY_PUBLIC_KEY,
  signType: 'RSA2',
  gateway: 'https://openapi.alipay.com/gateway.do'
});

async function createAppPayOrder() {
  const orderStr = alipaySdk.sdkExec('alipay.trade.app.pay', {
    notifyUrl: 'https://example.com/api/alipay/notify',
    bizContent: {
      outTradeNo: '07E99000221227113937TFA8',
      totalAmount: '0.10',
      subject: '购买商品',
      productCode: 'QUICK_MSECURITY_PAY'
    }
  });

  // 将 orderStr 原样返回给移动端,不要再次拼接网关或重新编码。
  return orderStr;
}

不同 SDK 版本可能对 bizContent 中的字段采用驼峰或下划线命名,具体应以当前 SDK 的类型定义和实际文档为准。最终生成的 biz_content 中必须包含:

"product_code": "QUICK_MSECURITY_PAY"

私钥只能保存在服务端,不能放进 App。

客户端应记录完整支付结果

以 Android 为例,应保留支付 SDK 返回的完整结果,不能只记录 resultStatus:

PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderStr, true);

String resultStatus = result.get("resultStatus");
String resultData = result.get("result");
String memo = result.get("memo");

Log.i("Alipay", "resultStatus=" + resultStatus);
Log.i("Alipay", "result=" + resultData);
Log.i("Alipay", "memo=" + memo);

需要重点检查:

  • resultStatus 是否确实为 6001。
  • memo 是否包含补充信息。
  • result 是否为空。
  • 传入 payV2() 的字符串是否与服务端生成的字符串完全一致。
  • 是否调用了两次支付方法。
  • 支付页面出现后,是否发生了返回、关闭或 Activity 生命周期变化。

日志可以记录 app_id、out_trade_no、时间和结果状态,但不能记录私钥,也不建议长期完整保存带签名的支付参数。

最可靠的定位方法

第一步:区分客户端取消和接口失败

如果回调为:

resultStatus=6001

并且 result、memo 中没有服务端错误信息,应先按“客户端取消”处理,不必继续寻找并不存在的 sub_code。

如果返回的是:

resultStatus=4000

同时 result 中包含 code、sub_code、msg 或 sub_msg,再根据服务端错误检查参数、签名或应用配置。

第二步:查询订单的最终状态

客户端返回结果不能作为最终入账依据。收到 6001、8000、6002 或 6004 后,可以由服务端调用 alipay.trade.query,使用原来的 out_trade_no 查询交易状态。

const queryResult = await alipaySdk.exec('alipay.trade.query', {
  bizContent: {
    outTradeNo: '07E99000221227113937TFA8'
  }
});

处理方式如下:

  • 查询到 TRADE_SUCCESS,或收到验签成功的异步通知时,按支付成功处理。
  • 查询到待支付状态时,说明订单尚未完成,可以允许用户重新支付。
  • 查询不到交易时,通常表示订单没有成功创建,或没有进入有效支付流程。
  • 查询接口返回 code、sub_code 时,根据这些服务端错误继续排查。

实际交易状态应以服务端异步通知和主动查询结果为准,不能只依赖客户端返回的 9000 或 6001。

第三步:使用最小参数重新生成订单

排查时不要复用旧的 orderStr,因为其中的时间戳和订单号可能已经失效或重复。每次测试都应:

  • 生成新的 out_trade_no。
  • 使用当前时间生成签名参数。
  • 保留 product_code。
  • 使用字符串金额,如 "0.10"。
  • 由 sdkExec() 一次生成订单串。
  • 将结果原样传给客户端,不再编码或拼接字符串。

还需要核对的配置

如果修正订单格式后出现 4000 或明确的服务端错误,再检查以下配置:

  • app_id 是否属于当前应用。
  • App 支付能力是否已开通并生效。
  • 应用公钥与服务端私钥是否配对。
  • 使用的支付宝公钥是否属于同一应用和环境。
  • 沙箱应用、沙箱网关和沙箱账号是否配套使用。
  • 正式环境是否使用正式网关和正式应用配置。
  • 签名算法是否为 RSA2。
  • 服务端和客户端传递 orderStr 时,是否再次执行了 encodeURIComponent。

6001 应优先理解为用户取消支付,不一定有可供查询的详细错误码。当前订单参数仍需补充 product_code,同时确认传给 App 支付 SDK 的内容不带网关 URL。修正后,再结合完整的客户端回调、异步通知和 alipay.trade.query 判断交易停在哪个阶段。

备注:内容仅供参考。