PAYATHON 2026

支付宝周期扣款先签约后支付提示交易订单处理失败的原因

支付阿杰

结论

请求参数的格式有明显问题,主要包括:

  • third_party_type 的实际值是 " PARTNER ",应改为 "PARTNER"。
  • format 的实际值是 json,应改为 json。
  • URL 中重复传入了两次 sign,只应保留一个。

这些问题可能导致支付宝无法正确校验业务参数或签名,页面最终只显示“交易订单处理失败,请稍后再试”。参数修正后,需要根据全部最终参数重新生成签名,原来的 sign 不能继续使用。

请求中存在的问题

对 biz_content 进行 URL 解码后,内容如下:

{
  "access_params": {
    "channel": "ALIPAYAPP"
  },
  "agreement_effect_type": "DIRECT",
  "external_agreement_no": "20221216092724bai6yRKl",
  "period_rule_params": {
    "execute_time": "2022-12-18",
    "period": 1,
    "period_type": "MONTH",
    "single_amount": "13.0"
  },
  "personal_product_code": "CYCLE_PAY_AUTH_P",
  "product_code": "CYCLE_PAY_AUTH",
  "sign_scene": "INDUSTRY|SVIEW",
  "sign_validity_period": "2m",
  "third_party_type": " PARTNER "
}

third_party_type 的值前后带有空格。支付宝接口通常会精确匹配枚举值,因此 " PARTNER " 和 "PARTNER" 会被视为两个不同的字符串。正确写法是:

"third_party_type": "PARTNER"

公共参数中还有以下内容:

format= json 

应改为:

format=json

请求末尾还出现了两个完全相同的 sign:

...&sign=签名值&sign_type=RSA2&timestamp=...&version=1.0&sign=签名值

重复参数可能造成验签时取值不一致。不同的解析组件可能读取第一个值、最后一个值,或者将两个值解析为数组,因此需要删除重复的 sign。

修正步骤

1. 清理业务参数中的空格

将业务参数改为:

{
  "access_params": {
    "channel": "ALIPAYAPP"
  },
  "agreement_effect_type": "DIRECT",
  "external_agreement_no": "20221216092724bai6yRKl",
  "period_rule_params": {
    "execute_time": "2022-12-18",
    "period": 1,
    "period_type": "MONTH",
    "single_amount": "13.0"
  },
  "personal_product_code": "CYCLE_PAY_AUTH_P",
  "product_code": "CYCLE_PAY_AUTH",
  "sign_scene": "INDUSTRY|SVIEW",
  "sign_validity_period": "2m",
  "third_party_type": "PARTNER"
}

不要依赖接入方或支付宝自动执行 trim()。对于枚举型参数,应直接传入文档规定的值。

2. 修正公共参数

公共参数至少应满足以下要求:

method=alipay.user.agreement.page.sign
format=json
charset=utf-8
sign_type=RSA2
version=1.0

每个参数只能出现一次。参数名、大小写和参数值必须与签名时使用的内容完全一致。

3. 重新生成签名

只要修改了 third_party_type、format 或其他参数,原签名就会失效。正确的处理顺序是:

  1. 生成最终的 biz_content。
  2. 组装所有需要参与签名的公共参数。
  3. 按支付宝的签名规则生成 RSA2 签名。
  4. 对最终请求参数进行 URL 编码。
  5. 确认 URL 中只有一个 sign。

不能先完成签名,再手动修改 URL 中的空格、JSON 内容或编码结果。

Java 调用示例

建议使用支付宝 Java SDK 构造请求,避免手动拼接完整的 alipays:// URL:

AlipayClient alipayClient = new DefaultAlipayClient(
    gatewayUrl,
    appId,
    merchantPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

AlipayUserAgreementPageSignRequest request =
    new AlipayUserAgreementPageSignRequest();

request.setNotifyUrl(notifyUrl);
request.setReturnUrl(returnUrl);

String bizContent = """
{
  "product_code": "CYCLE_PAY_AUTH",
  "personal_product_code": "CYCLE_PAY_AUTH_P",
  "sign_scene": "INDUSTRY|SVIEW",
  "external_agreement_no": "20221216092724bai6yRKl",
  "agreement_effect_type": "DIRECT",
  "sign_validity_period": "2m",
  "third_party_type": "PARTNER",
  "access_params": {
    "channel": "ALIPAYAPP"
  },
  "period_rule_params": {
    "period_type": "MONTH",
    "period": 1,
    "execute_time": "2022-12-18",
    "single_amount": "13.0"
  }
}
""";

request.setBizContent(bizContent);

AlipayUserAgreementPageSignResponse response =
    alipayClient.pageExecute(request);

String orderString = response.getBody();

具体的请求类和调用方式取决于所使用的支付宝 Java SDK 版本。如果当前 SDK 的类名或方法签名不同,应以实际依赖版本提供的接口为准。应由 SDK 统一处理参数排序、签名和编码,不要在 SDK 返回结果后再次添加 sign。

还需要检查的配置

如果清理参数并重新签名后仍然失败,还需要依次检查:

  • 当前 app_id 是否已经开通周期扣款及对应的产品能力。
  • product_code、personal_product_code 和 sign_scene 是否与商户实际签约的产品配置一致。
  • 商户私钥是否与该应用配置的支付宝公钥匹配。
  • external_agreement_no 是否在商户侧保持唯一。
  • execute_time 是否符合周期规则及接口对首次执行日期的限制。
  • notify_url 和 return_url 是否符合当前接口的地址要求,并且可以从公网正常访问。
  • 从生成请求到发起请求期间,是否修改过 biz_content、编码方式或公共参数。

题目中的请求时间是 2022 年,示例里的 execute_time 也已经过期,不能直接用于新的请求。重新测试时,应根据当前时间和已开通产品的规则,生成新的执行日期、时间戳和签名。

应先修正 " PARTNER "、json 和重复 sign 这三个已经确认的问题,再根据最终参数重新生成完整请求。如果只是删除空格却继续使用旧签名,验签仍会失败,签约也无法完成。

备注:内容仅供参考。