android端支付宝支付返回6001,官网demo支付成功
结论
支付宝 Android SDK 返回 resultStatus=6001,标准含义是“用户取消支付”。如果用户没有主动取消,拉起支付宝后却立即返回 6001,问题通常不在 SDK,而在服务端生成的订单字符串。签名、编码、参数拼接或传输中的错误,都可能让支付流程无法继续。
官网 Demo 支付成功,只能说明支付宝客户端、SDK 集成和设备环境基本正常,不能证明业务服务器生成的订单参数没有问题。
重点排查原因
1. 订单字符串在传输过程中被修改
这是最常见的原因。服务端生成 orderInfo 后,必须原样传给 Android 客户端,再原样传入 PayTask.pay()。
常见错误有:
+被转换成空格%、&、=等字符被错误处理- 整个订单字符串被重复 URL 编码或解码
- JSON 序列化造成转义
- 客户端拆开订单字符串后重新拼接
- 通过表单传输时,
application/x-www-form-urlencoded改变了参数内容 - 日志或数据库字段长度不足,订单字符串被截断
建议分别记录以下内容:
- 服务端签名完成后的最终订单字符串
- Android 收到的原始字符串
- 传入
PayTask.pay()前的字符串
逐字比较这三处内容,并确认字符串长度一致。完整签名和订单敏感信息只能在测试环境中记录,生产环境不要直接输出。
2. 签名方式或密钥配置不一致
服务端应使用与支付宝开放平台应用配置匹配的应用私钥签名。需要逐项确认:
app_id是否属于当前应用- 应用私钥是否与开放平台配置的应用公钥配对
- 签名方式是否为约定的
RSA2 sign_type是否与实际签名算法一致- 字符集是否统一为
UTF-8 - 是否混用了正式环境和沙箱环境
- 是否误用支付宝公钥进行订单签名
支付宝公钥通常用于验签,应用私钥用于业务请求签名,两者不能混用。
3. 服务端拼接的待签名内容不正确
签名应在服务端完成,客户端不应自行拼接参数或重新签名。
签名前通常要确认:
- 参数名称正确
- 空值参数按照所用 SDK 的规则处理
- 参数排序符合签名规则
biz_content是合法 JSON- 使用编码前的待签名字符串进行签名
- 最终请求字符串中的参数按接口要求编码
- 金额、订单号等字段没有多余空格或不可见字符
如果项目使用支付宝提供的服务端 SDK,建议直接通过 SDK 生成 APP 支付所需的订单字符串,以减少手工排序、编码和签名引起的错误。
推荐解决步骤
第一步:确认用户是否真的取消了支付
在 Android 端打印完整的同步结果:
PayTask alipay = new PayTask(activity);
Map<String, String> result = alipay.payV2(orderInfo, true);
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
String resultData = result.get("result");
Log.d("AliPay", "resultStatus=" + resultStatus);
Log.d("AliPay", "memo=" + memo);
Log.d("AliPay", "result=" + resultData);
如果用户点击了返回键或关闭按钮,返回 6001 是正常结果,不需要当作支付故障处理。
如果支付宝拉起后立即返回,则要继续检查订单参数。memo 和 result 可以提供排查线索,但最终支付状态不能只看客户端返回值。
第二步:确保客户端不处理订单字符串
服务端可以返回以下结构:
{
"code": 0,
"orderInfo": "app_id=...&biz_content=...&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&sign=..."
}
Android 端直接取出 orderInfo:
String orderInfo = response.getOrderInfo();
new Thread(() -> {
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderInfo, true);
activity.runOnUiThread(() -> {
String resultStatus = result.get("resultStatus");
handlePayResult(resultStatus);
});
}).start();
不要再做以下处理:
// 不要重复编码
String encoded = URLEncoder.encode(orderInfo, "UTF-8");
// 不要拆分后重新排序或拼接
String[] params = orderInfo.split("&");
// 不要在客户端重新签名
String sign = signOnAndroid(orderInfo);
第三步:对比服务端与客户端收到的内容
测试环境可以记录字符串长度和部分特征,避免在日志中直接暴露完整订单:
Log.d("AliPay", "orderInfo length=" + orderInfo.length());
Log.d("AliPay", "containsSpace=" + orderInfo.contains(" "));
重点检查 sign 参数中是否出现空格。如果服务端原始内容包含 +,客户端收到后却变成了空格,通常是传输层执行了表单解码。
遇到这种情况,应优先通过 JSON 返回订单字符串,并确保客户端网络框架将其作为普通字符串读取,不要额外调用 URLDecoder.decode()。
第四步:核对服务端配置
逐项确认以下配置属于同一个支付宝应用,并来自同一套环境:
app_id
应用私钥
支付宝公钥或支付宝证书
sign_type=RSA2
charset=utf-8
gateway
如果使用沙箱应用生成订单,却调用正式环境,或者使用 A 应用的 app_id,却用 B 应用的私钥签名,订单都无法正常处理。
第五步:检查业务参数
至少确认以下参数:
{
"out_trade_no": "业务系统中唯一的订单号",
"total_amount": "0.01",
"subject": "订单标题",
"product_code": "QUICK_MSECURITY_PAY"
}
需要注意:
out_trade_no不应重复用于不同订单。total_amount建议使用符合接口要求的十进制字符串。biz_content必须是合法 JSON。product_code应符合 APP 支付场景。- 订单字符串不能被数据库字段、网关或代理截断。
服务端示例
下面的示例只展示典型调用结构。具体类名和初始化方式应以项目实际使用的支付宝服务端 SDK 版本为准:
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
appPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(outTradeNo);
model.setTotalAmount(totalAmount);
model.setSubject(subject);
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(notifyUrl);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderInfo = response.getBody();
response.getBody() 返回的内容应直接交给 Android 客户端。不要取出其中的参数再次手工拼接,也不要对整个字符串重复进行 URL 编码。
支付结果处理注意事项
6001 只表示客户端支付流程被取消,业务系统不能据此直接关闭订单。用户取消后,支付结果仍可能因网络延迟等原因稍后到达服务端。
业务系统应以以下结果为准:
- 支付宝异步通知
- 服务端主动查询到的交易状态
- 验签通过后的服务端结果
客户端返回 9000 也不能作为最终到账依据,更不能只根据客户端结果直接发货。
如果官网 Demo 正常,而业务订单拉起后立即返回 6001,应先比较“服务端最终订单字符串”和“Android 实际传入 SDK 的字符串”是否完全一致,再检查密钥、app_id、运行环境和签名配置。这类问题多数出在订单字符串被转码、截断或重复编码的环节。
备注:内容仅供参考。
