批次下单接口 order_title 长度及特殊字符限制
明确结论
仅凭接口文档中的 string(64),只能确认 order_title 的最大长度为 64。文档没有说明这个 64 按字符数、UTF-8 字节数还是其他编码口径计算,因此不能直接理解为“最多 64 个汉字”。
为减少验签成功后仍被接口拒绝的情况,生产环境可以采用更严格的校验:
order_title经 UTF-8 编码后不得超过 64 字节。- 常用汉字在 UTF-8 中通常占 3 字节。如果标题全部由常用汉字组成,建议最多填写 21 个。
- 英文字母、数字和半角符号通常占 1 字节。
- Emoji 和部分生僻汉字通常占 4 字节。
- 文档没有提供特殊字符黑名单,不能据此断言某个字符一定被官方禁止。生产系统可以使用白名单,只允许汉字、字母、数字、空格和少量常用标点。
- 批量付款的支付密码通常在支付宝收银台输入,不应通过批次下单接口传递。密码格式、连续输错限制和风控校验应以收银台的实际提示为准。
为什么不能把 string(64) 直接理解为 64 个汉字
接口字段中的 string(64) 通常表示字符串的最大长度,但不同系统的计算方式可能不同:
- 按 Unicode 字符数量计算;
- 按 UTF-8 编码后的字节数计算;
- 按 Java UTF-16 代码单元计算;
- 接口层按字符数校验,存储层或下游系统再按字节数校验。
例如,“付款”包含 2 个 Unicode 字符,采用 UTF-8 编码后则占 6 字节:
付:3 字节
款:3 字节
合计:6 字节
几类常见内容的长度对比如下:
| 内容 | 字符数 | UTF-8 字节数 |
|---|---|---|
ABC123 | 6 | 6 |
批量付款 | 4 | 12 |
付款-2026 | 7 | 11 |
😀 | 1 | 4 |
如果接口最终按字节数校验,64 个常用汉字大约占 192 字节,会明显超过限制。官方文档没有进一步说明时,按 UTF-8 字节数限制更稳妥。
推荐的校验步骤
提交批次下单请求前,可以按以下顺序处理 order_title:
- 检查字段是否为空;
- 去除首尾空白字符;
- 拒绝换行符、制表符和不可见控制字符;
- 根据业务需要限制允许使用的字符;
- 计算 UTF-8 字节数,确认不超过 64;
- 使用生产环境的实际编码完成序列化和签名,签名后不要再修改标题。
可以优先允许以下字符:
- 中文;
- 英文字母;
- 数字;
- 普通空格;
-、_、(、)、(、)等业务确实需要的常用标点。
以下内容建议谨慎使用或直接拦截:
\r、\n、\t等控制字符;- Emoji;
- 零宽空格等不可见字符;
- HTML 标签;
- URL 编码片段;
- 可能影响日志、CSV 或页面展示的符号组合。
这些拦截措施是调用方的防御性校验,并不代表相关字符都在支付宝官方黑名单中。如果业务必须使用某个符号,应通过沙箱或小额生产请求进行验证,并以接口返回结果为准。
Java 校验示例
下面的实现将 UTF-8 字节数限制为 64,并拒绝控制字符:
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
public final class OrderTitleValidator {
private static final int MAX_UTF8_BYTES = 64;
private static final Pattern CONTROL_CHARS =
Pattern.compile("[\\p{Cc}\\p{Cf}]");
public static String validate(String orderTitle) {
if (orderTitle == null || orderTitle.trim().isEmpty()) {
throw new IllegalArgumentException("order_title 不能为空");
}
String normalized = orderTitle.trim();
if (CONTROL_CHARS.matcher(normalized).find()) {
throw new IllegalArgumentException(
"order_title 不能包含控制字符或不可见格式字符"
);
}
int byteLength =
normalized.getBytes(StandardCharsets.UTF_8).length;
if (byteLength > MAX_UTF8_BYTES) {
throw new IllegalArgumentException(
"order_title 的 UTF-8 编码长度不能超过 64 字节,当前为 "
+ byteLength + " 字节"
);
}
return normalized;
}
}
如果业务需要使用字符白名单,可以增加以下校验:
private static final Pattern ALLOWED_CHARS =
Pattern.compile("^[\\p{IsHan}A-Za-z0-9 _\\-()()]+$");
if (!ALLOWED_CHARS.matcher(normalized).matches()) {
throw new IllegalArgumentException(
"order_title 包含不支持的字符"
);
}
白名单需要根据实际业务调整。在没有官方依据的情况下,不要把示例正则视为支付宝完整的字符规则。
JavaScript 校验示例
在浏览器或 Node.js 中,可以使用 TextEncoder 计算 UTF-8 字节数:
function validateOrderTitle(value) {
if (typeof value !== "string" || value.trim() === "") {
throw new Error("order_title 不能为空");
}
const orderTitle = value.trim();
// 拒绝常见控制字符和不可见格式字符
if (/[\p{Cc}\p{Cf}]/u.test(orderTitle)) {
throw new Error("order_title 不能包含控制字符或不可见格式字符");
}
const byteLength = new TextEncoder().encode(orderTitle).length;
if (byteLength > 64) {
throw new Error(
`order_title 的 UTF-8 编码长度不能超过 64 字节,当前为 ${byteLength} 字节`
);
}
return orderTitle;
}
不要使用下面的写法计算 UTF-8 字节数:
orderTitle.length
JavaScript 的 length 计算的是 UTF-16 代码单元。遇到汉字、Emoji 或组合字符时,其结果可能与 UTF-8 字节数不同。
关于批量付款的支付密码
order_title 只是批次下单请求中的转账标题,不是支付密码字段,也不应包含密码、验证码或其他敏感信息。
批量付款进入支付宝收银台后,支付密码一般由用户在支付宝提供的页面中输入。处理时应注意:
- 不要通过接口参数、日志、数据库或前端埋点采集支付密码;
- 不要把支付密码拼接到
order_title、备注或扩展字段中; - 密码长度、字符组成、错误次数和账户风控限制由支付宝收银台控制;
- 是否支持免密、证书、复核或其他安全能力,取决于签约产品、账户状态和当时的收银台规则;
- 如果支付页面提示标题含有非法字符或长度超限,应记录支付宝返回的错误码和原始错误信息,再据此调整校验规则。
在字段说明不够明确时,建议将 order_title 控制在 64 个 UTF-8 字节以内,并通过业务白名单限制字符。特殊字符和支付密码规则不能根据 string(64) 自行推断,应以对应产品文档、接口错误码和收银台的实际校验结果为准。
备注:内容仅供参考。
