唤起支付宝app支付时返回6001错误如何解决?
结论
支付宝客户端返回 resultStatus=6001,通常表示用户取消了当前操作,并不是服务端用于说明具体参数错误的业务码。
当前调用的接口是 alipay.user.agreement.page.sign,对应周期扣款协议签约,并非普通 App 支付。如果用户没有主动取消,支付宝被唤起后却立即返回 6001,建议优先检查以下问题:
- App 是否正确接收并传递了支付宝的同步返回结果;
- 签约串是否经过重复 URL 编码,或出现截断、拼接错误;
- 签约产品、应用权限和
sign_scene是否已经配置; notify_url是否合法且能从公网访问;biz_content中各字段的类型和取值是否符合当前接口文档。
仅凭 6001 无法判断具体是哪个业务参数有误。排查时还要结合支付宝 SDK 返回的 memo、result 和服务端接口日志。
请求中应优先检查的问题
1. notify_url 地址明显异常
请求中的地址解码后是:
http:///pay/AliNotify/sign
这个地址在 http:// 后缺少域名或 IP,而且多了一个 /,不是有效的公网回调地址。应改为完整的 HTTPS 地址,例如:
https://pay.example.com/AliNotify/sign
通知地址通常需要满足以下条件:
- 支付宝服务器可以从公网访问;
- 不使用
localhost、内网 IP 或相对路径; - 建议使用 HTTPS;
- 不依赖登录状态、Cookie 或前端跳转;
- 可以接收支付宝发送的 POST 通知;
- 收到通知后执行验签,并按接口要求返回成功响应。
错误的 notify_url 不一定会直接产生 6001,但会导致签约结果通知失败,因此必须修正。
2. external_agreement_no 应按字符串处理
当前 JSON 中的值是数字:
"external_agreement_no": 1659146366
商户协议号是业务标识,不用于数值计算,建议改为字符串:
"external_agreement_no": "1659146366"
这样可以避免长编号精度丢失、前导零消失,以及不同语言在 JSON 序列化时产生类型差异。
每次创建签约请求时,还要确保该编号符合接口规定,并且在商户侧唯一。不要直接把秒级时间戳当作唯一编号,因为并发请求可能产生重复值。
3. 确认签约产品和场景已经开通
请求中包含:
"personal_product_code": "CYCLE_PAY_AUTH_P",
"sign_scene": "INDUSTRY|CARRENTAL"
这两个字段不是普通描述,不能任意填写。它们必须与支付宝为当前 app_id 开通的周期扣款产品和签约场景一致。
需要在支付宝开放平台或商家平台确认:
app_id=2021003138687250对应的应用是否已经上线;- 应用是否已经签约并开通周期扣款能力;
CYCLE_PAY_AUTH_P是否适用于当前账户和应用;INDUSTRY|CARRENTAL是否为已配置并通过审核的签约场景;- 应用公钥、支付宝公钥和应用网关配置是否属于同一个环境;
- 正式环境的应用、密钥和支付宝客户端调用地址是否混用了沙箱配置。
如果产品或场景尚未开通,应先完成产品签约,或联系支付宝技术支持确认权限。不要靠修改 sign_scene 猜测可用值。
4. 检查参数是否已经过期
示例中的请求时间是:
timestamp=2022-07-30 09:59:27
同时还有:
"execute_time": "2022-07-30"
如果现在仍在重复使用这段完整请求,它已经失效。每次调用时都应重新生成:
timestamp;- 商户协议号;
- 需要动态计算的首次执行时间;
- RSA2 签名。
execute_time 的格式和允许范围应以当前周期扣款接口文档为准。例如,首次扣款日期能否设为当天、是否必须晚于签约日若干天,都可能受具体产品规则限制。
服务端的正确生成方式
签约串应通过支付宝服务端 SDK 生成,不建议手工拼接参数。下面仅展示基本结构,具体类名和方法以项目实际安装的 PHP SDK 为准:
<?php
$aop = new AopClient();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = '你的应用APPID';
$aop->rsaPrivateKey = '你的应用私钥';
$aop->alipayrsaPublicKey = '支付宝公钥';
$aop->signType = 'RSA2';
$aop->postCharset = 'UTF-8';
$aop->format = 'json';
$request = new AlipayUserAgreementPageSignRequest();
$bizContent = [
'personal_product_code' => 'CYCLE_PAY_AUTH_P',
'external_agreement_no' => 'AGREEMENT_' . date('YmdHis'),
'sign_scene' => 'INDUSTRY|CARRENTAL',
'access_params' => [
'channel' => 'ALIPAYAPP',
],
'period_rule_params' => [
'period_type' => 'DAY',
'period' => 30,
'execute_time' => date('Y-m-d', strtotime('+1 day')),
'single_amount' => '30.00',
],
'prod_params' => [
'auth_biz_params' => '动力万家',
],
];
$request->setBizContent(
json_encode($bizContent, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
$request->setNotifyUrl('https://pay.example.com/AliNotify/sign');
$orderString = $aop->sdkExecute($request);
// 将原始签约串返回给客户端,不要在业务层再次 urlencode。
echo $orderString;
示例中的日期、产品参数和 auth_biz_params 只用于说明构造方式,不能替代支付宝为具体商户配置的实际规则。
客户端调用时不要重复编码
服务端 SDK 返回的签约串已经包含 URL 编码和 RSA2 签名。客户端应将完整字符串直接交给支付宝 SDK,不要再次执行以下操作:
urlencode
encodeURIComponent
URLDecoder.decode
重新排序参数
拆分后重新拼接
JSON 转义整个签约串
二次编码、解码或改变参数顺序,都可能导致签名校验失败。
Android 客户端应保存完整的返回结果:
Map<String, String> result = new PayTask(activity)
.payV2(orderString, true);
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
String rawResult = result.get("result");
Log.i("Alipay", "resultStatus=" + resultStatus);
Log.i("Alipay", "memo=" + memo);
Log.i("Alipay", "result=" + rawResult);
如果实际使用的签约 SDK 调用方法不是 payV2,处理方式也一样:保留支付宝返回的状态、提示信息和原始业务结果,不要只记录 6001。
建议的排查顺序
- 确认用户是否点击了返回、关闭或取消按钮。如果确实取消了,
6001属于正常结果,可以提示用户重新发起签约。 - 记录客户端收到的完整
resultStatus、memo和result。 - 修正
notify_url,确保地址包含有效域名并能从公网访问。 - 每次都由服务端重新生成签约串,不要复用示例中的旧时间戳和旧签名。
- 将
external_agreement_no改为字符串,并确保编号唯一。 - 对比客户端收到的签约串和服务端生成的原始字符串,检查是否发生截断或二次编码。
- 确认 App 使用的
app_id、应用私钥和支付宝公钥属于同一个应用和环境。 - 在支付宝后台确认周期扣款产品和
INDUSTRY|CARRENTAL场景已经开通。 - 如果客户端仍然立即返回
6001,请使用新请求重现问题,并向支付宝技术支持提供app_id、接口名称、请求时间、完整memo、支付宝返回的业务码和请求流水号。不要提供私钥或完整签名。
注意事项
6001 只能按“客户端操作被取消”处理,不能用来判断签名或签约是否成功。最终签约状态应以支付宝异步通知为主,必要时再调用协议查询接口核实。
不要把应用私钥、完整请求签名或用户敏感信息写入前端日志。生产日志可以记录商户协议号、请求时间和支付宝流水号,方便后续定位问题。
备注:内容仅供参考。
