alipay.marketing.activity.voucher.create 参数冲突如何解决?
结论
在当前调用场景中,voucher_use_rule_info.voucher_max_use_times 应完全省略,由支付宝服务端使用默认核销次数。
前后两次提示看似矛盾,通常与 AlipaySDKNet 对该字段的类型定义和序列化方式有关。如果字段使用非 nullable 数值类型,即使没有赋值,C# 也会将其初始化为 0。一旦 SDK 把这个默认值序列化并发送,服务端就会提示该值“必须大于或等于 1”。
将字段设为 1 后,参数值本身通过了校验,但接口还会检查当前业务场景是否允许商户传入该字段。如果不允许,就会返回“当前接口不支持的参数”。
所以,解决办法不是将值改成 1,而是确认最终提交的 biz_content 中没有 voucher_max_use_times。
为什么会出现两个看似冲突的错误
接口参数通常要经过多层校验:
- 字段值校验:收到
voucher_max_use_times=0时,返回“必须大于或等于 1”。 - 接口或业务场景校验:收到
voucher_max_use_times=1时,可能发现当前券类型、接口版本或业务模式不允许传入该字段,于是返回“当前接口不支持的参数”。
没有显式设置属性,不等于请求中一定没有这个字段。假设 SDK 模型中的属性定义如下:
public long VoucherMaxUseTimes { get; set; }
该属性未赋值时,默认值是 0。如果 SDK 序列化时不忽略数值类型的默认值,请求中仍可能包含:
{
"voucher_use_rule_info": {
"voucher_max_use_times": 0
}
}
这可以解释第一次错误。
设置下面这行代码后:
voucherUseRuleInfo.VoucherMaxUseTimes = 1;
请求会明确传入该字段。服务端随后发现当前接口场景不接受它,因此出现第二次错误。
正确处理方式
1. 删除业务代码中的赋值
先移除这一行:
voucherUseRuleInfo.VoucherMaxUseTimes = 1;
只删除赋值可能还不够,还需要检查 SDK 是否会把默认值 0 序列化出去。
2. 检查实际发送的 biz_content
排查时应查看最终 HTTP 请求中的 biz_content,不能只检查 C# 对象。正确的请求中不应出现:
"voucher_max_use_times": 0
也不应出现:
"voucher_max_use_times": 1
同样不要发送:
"voucher_max_use_times": null
这个字段需要从请求中完全消失。
还要注意字段名称的差异。C# 属性名是 VoucherMaxUseTimes,序列化后的 JSON 字段通常是 voucher_max_use_times,错误信息中可能显示为 voucherMaxUseTimes。这三个名称指向同一个参数。
3. 优先升级 AlipaySDKNet
先确认当前使用的 AlipaySDKNet 和接口模型是否为可获得的较新版本。新版接口模型可能已经将该属性改为 nullable 类型,或者修正了默认值的序列化行为。
更新 DLL 后,也不要继续使用从旧版本复制出来的 Model 类。需要确认项目实际引用的 VoucherUseRuleInfo 来自哪个程序集或命名空间。
4. nullable 属性应保持 null
如果当前 SDK 将该属性定义为 nullable 类型,例如:
public long? VoucherMaxUseTimes { get; set; }
不要为其赋值,或者明确将其设为 null:
VoucherUseRuleInfo voucherUseRuleInfo = new VoucherUseRuleInfo();
VoucherUseTimeInfo voucherUseTimeInfo = new VoucherUseTimeInfo
{
PeriodType = "ABSOLUTE",
AbsolutePeriodInfo = new VoucherAbsolutePeriodInfo
{
ValidBeginTime = "2026-10-01 00:00:00",
ValidEndTime = "2026-12-31 23:59:59"
}
};
voucherUseRuleInfo.VoucherUseTimeInfo = voucherUseTimeInfo;
voucherUseRuleInfo.VoucherMaxUseTimes = null;
model.VoucherUseRuleInfo = voucherUseRuleInfo;
这样处理的前提是 SDK 序列化器会忽略 null 属性。完成修改后,仍要通过请求日志确认最终 JSON 中没有这个字段。
5. 非 nullable 属性需要修正模型或序列化结果
如果该属性是 long、int 等非 nullable 类型,而且 SDK 必然发送默认值,可以在可控的 SDK 模型源码中将其改成 nullable 类型:
[JsonProperty("voucher_max_use_times")]
public long? VoucherMaxUseTimes { get; set; }
修改后不要为该属性赋值。
如果项目引用的是 NuGet 包中的预编译模型,不建议直接修改缓存目录中的包文件。可以采用以下方式:
- 升级到已经修正该问题的 SDK;
- 使用项目内可维护的模型或 SDK 源码版本;
- 在发送前构造请求 JSON,并删除
voucher_max_use_times。
自行构造 biz_content 时,结构可以写成:
var bizModel = new
{
out_biz_no = "yaqi1111111111",
merchant_access_mode = "SELF_MODE",
activity_base_info = new
{
activity_name = "生活缴费红包"
},
voucher_use_rule_info = new
{
voucher_use_time_info = new
{
period_type = "ABSOLUTE",
absolute_period_info = new
{
valid_begin_time = "2026-10-01 00:00:00",
valid_end_time = "2026-12-31 23:59:59"
}
}
// 不要添加 voucher_max_use_times
}
};
如何将 JSON 设置到请求中,应以当前 AlipaySDKNet 版本公开的请求方法为准,不要假定所有版本都提供相同的重载。
建议调整后的核心代码
// 设置券核销限制
VoucherUseRuleInfo voucherUseRuleInfo = new VoucherUseRuleInfo();
VoucherUseTimeInfo voucherUseTimeInfo = new VoucherUseTimeInfo();
voucherUseTimeInfo.PeriodType = "ABSOLUTE";
VoucherAbsolutePeriodInfo absolutePeriodInfo =
new VoucherAbsolutePeriodInfo();
absolutePeriodInfo.ValidBeginTime = "2026-10-01 00:00:00";
absolutePeriodInfo.ValidEndTime = "2026-12-31 23:59:59";
voucherUseTimeInfo.AbsolutePeriodInfo = absolutePeriodInfo;
voucherUseRuleInfo.VoucherUseTimeInfo = voucherUseTimeInfo;
// 当前接口场景不支持显式传入该参数。
// 不要设置:voucherUseRuleInfo.VoucherMaxUseTimes = 1;
model.VoucherUseRuleInfo = voucherUseRuleInfo;
这段修改只有在 SDK 不会自动将未赋值的 VoucherMaxUseTimes 序列化成 0 时才有效。如果请求日志中仍然能看到该字段,就需要继续调整 SDK 模型或序列化配置。
其他注意事项
- 不要根据异常信息直接增加参数。如果先后出现“值不合法”和“字段不支持”,应先检查实际发送的请求报文。
- 示例中的
2024-08-01至2024-12-31已经过期。实际调用时,发放时间和券有效时间必须符合接口规则,否则删除该字段后仍可能收到日期相关错误。 VoucherCustomerGuideInfo当前是空对象。如果没有引导信息,建议不要设置它,避免 SDK 发送{}后触发额外校验。available_pids、券图片素材 ID、资金模式和商户接入模式也必须与实际签约能力一致。- 如果升级 SDK、将属性改为 nullable,并确认请求中已经没有该字段后,服务端仍返回同样的错误,应保存脱敏后的完整
biz_content、接口网关地址、SDK 版本和支付宝响应中的sub_code/sub_msg,再联系支付宝开放平台技术支持,核对当前应用对应的接口版本和产品权限。
备注:内容仅供参考。
