PAYATHON 2026

alipay-easysdk 创建支付时 userId 长度不合法

支付老李

结论

不要将 buyer_open_id、应用用户 ID、手机号或授权码传给 alipay-easysdk 的 buyerId 参数。

旧版 EasySDK 的支付创建方法通常会把最后一个参数序列化为 buyer_id。如果当前支付宝接口要求使用 buyer_open_id,应优先升级到支持该字段的 SDK。如果 EasySDK 仍未提供对应参数,则改用支付宝 OpenAPI SDK,直接构造 alipay.trade.create 请求,并设置 buyer_open_id。

原因

buyer_id 和 buyer_open_id 是两个不同的字段:

  • buyer_id:支付宝用户 ID。旧接口可能要求特定格式,不能传入普通的业务用户 ID。
  • buyer_open_id:支付宝提供的用户开放标识,需要通过支付宝授权流程获取。
  • 即使 EasySDK 方法中的 Java 参数名是 buyerId,最终发送的字段通常仍是 buyer_id。

因此,下面的调用存在风险:

Factory.Payment.Common().create(
    subject,
    outTradeNo,
    totalAmount,
    buyerOpenId
);

这里的 buyerOpenId 实际会作为 buyer_id 发送。由于两种标识的格式不同,支付宝校验时可能返回“userId 长度不合法”。

错误信息中的 userId 不一定对应请求 JSON 里的真实字段名,也可能只是服务端对用户标识参数使用的统一校验提示。

解决步骤

1. 确认当前传入的标识类型

检查创建支付时最后一个参数的来源。如果该参数来自用户授权接口,实际含义是 buyer_open_id,就不能继续传给旧版 EasySDK 的 buyerId 参数。

还要确认没有误传以下数据:

  • 商户系统自己的用户 ID
  • 手机号
  • auth_code
  • app_auth_token
  • 登录账号
  • 被截断的 buyer_open_id

不要通过补零、截断或拼接字符串来绕过长度校验。

2. 检查 EasySDK 是否支持 buyer_open_id

查看项目实际使用版本的方法签名和请求模型。如果新版 SDK 已提供 buyerOpenId、buyer_open_id 或相应的扩展参数入口,可以升级后改用该接口。

不同语言、不同版本的 EasySDK 支持范围可能不同,不能只看方法参数名称来判断最终发送的字段。应以实际依赖版本的源码、生成的请求 JSON 或对应 API 文档为准。

3. EasySDK 不支持时改用 OpenAPI SDK

如果当前 EasySDK 的 create 方法固定发送 buyer_id,又没有设置 buyer_open_id 的入口,可以直接通过支付宝 OpenAPI SDK 调用 alipay.trade.create。

下面是 Java 写法示例。具体类名以及 setter 是否可用,应以项目采用的 alipay-sdk-java 版本为准:

AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();

AlipayTradeCreateModel model = new AlipayTradeCreateModel();
model.setSubject(subject);
model.setOutTradeNo(outTradeNo);
model.setTotalAmount(totalAmount);
model.setBuyerOpenId(buyerOpenId);

request.setBizModel(model);

AlipayTradeCreateResponse response = alipayClient.execute(request);

if (!response.isSuccess()) {
    throw new IllegalStateException(
        "创建支付失败,code=" + response.getCode()
            + ", subCode=" + response.getSubCode()
            + ", subMsg=" + response.getSubMsg()
    );
}

如果当前 SDK 模型没有 setBuyerOpenId,可以先确认接口确实接受 buyer_open_id,再直接设置业务参数 JSON:

AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();

Map<String, Object> bizContent = new HashMap<>();
bizContent.put("subject", subject);
bizContent.put("out_trade_no", outTradeNo);
bizContent.put("total_amount", totalAmount);
bizContent.put("buyer_open_id", buyerOpenId);

request.setBizContent(objectMapper.writeValueAsString(bizContent));

AlipayTradeCreateResponse response = alipayClient.execute(request);

除非当前接口文档明确允许同时设置这两个字段,并说明了处理优先级,否则不要同时传入 buyer_id 和 buyer_open_id。

如果暂时必须继续使用旧版 EasySDK

只有确认当前接口仍接受 buyer_id,并且获取到的确实是支付宝用户 ID,才能继续调用旧方法:

Factory.Payment.Common().create(
    subject,
    outTradeNo,
    totalAmount,
    alipayBuyerId
);

这里的 alipayBuyerId 必须是真正的 buyer_id,不能用 buyer_open_id 代替。题述接口文档已经将 buyer_id 标记为弃用,因此这种写法只适合作为兼容方案,不适合新功能长期使用。

注意事项

  • buyer_open_id 必须通过支付宝认可的授权或用户标识获取流程取得,不能由商户自行生成。
  • 确认 buyer_open_id 与当前应用、账号和调用场景相匹配。
  • 更新 SDK 后仍需检查最终请求,确认发送的是 buyer_open_id,而不是只修改了本地变量名。
  • 排查日志可以记录字段名、长度和错误码,但不要完整打印用户标识、私钥、授权码或访问令牌。
  • 如果改用 buyer_open_id 后仍然报错,应结合支付宝返回的 code、sub_code 和 sub_msg 排查,不能只看“长度不合法”这一句提示。

备注:内容仅供参考。