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_codeapp_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排查,不能只看“长度不合法”这一句提示。
备注:内容仅供参考。
