数据校验基础:字段类型、长度、范围、必填项与格式校验
数据校验这事儿,说白了就是给金融协议做「体检」。我做了这么多年金融系统,见过太多因为校验不到位导致的线上事故。有一次凌晨三点被叫起来,就因为一个金额字段传了字符串,结果清算系统直接崩了。嗯,从那以后我对数据校验就特别较真。
今天咱们就把数据校验的五个基本功掰开揉碎讲清楚。你想想看,金融协议里每一笔交易都是真金白银,校验做不好,后果很严重。
1. 字段类型校验
类型校验是最基础的一关。我习惯把它叫做「第一道防线」。说白了就是检查数据是不是我们期望的类型。
核心原则:金融协议中,数字就是数字,字符串就是字符串,别让它们串门。
我在项目中遇到过最典型的例子:某支付接口把金额字段定义成字符串,结果上游系统传了个"12.34元"进来。你猜怎么着?解析直接报错,整条交易链路卡死。
常见的类型校验包括:
- 数字类型:检查是否为整数、浮点数、定点数
- 字符串类型:检查是否为UTF-8、ASCII等编码
- 布尔类型:检查是否为true/false或0/1
- 日期类型:检查是否为合法日期格式
// 我个人习惯这样写类型校验
function validateType(value, expectedType) {
switch(expectedType) {
case 'number':
return typeof value === 'number' && !isNaN(value);
case 'string':
return typeof value === 'string';
case 'boolean':
return typeof value === 'boolean';
case 'date':
return value instanceof Date && !isNaN(value.getTime());
default:
return false;
}
}
小技巧:JavaScript里typeof null返回'object',这是个历史遗留bug。我建议用Object.prototype.toString.call()来判断类型,更靠谱。
2. 长度校验
长度校验看着简单,但坑不少。金融协议里字段长度都有严格规定,比如银行账号、身份证号、交易流水号。
为什么会这样?因为后端数据库的字段长度是固定的。你传一个超长的字符串,要么被截断,要么直接报错。这两种情况在金融系统里都是灾难。
我曾经遇到过一个案例:某基金申购接口,订单号字段允许50个字符。结果上游系统传了个带空格和特殊字符的订单号,实际长度只有48,但加上空格后变成了52。嗯,数据库直接报字段超长,交易失败。
| 字段类型 | 常见长度限制 | 说明 |
|---|---|---|
| 银行账号 | 16-19位 | 国内银行卡号标准 |
| 身份证号 | 18位 | 含最后一位校验码 |
| 交易流水号 | 32位以内 | 各家银行标准不同 |
| 手机号 | 11位 | 中国大陆标准 |
// 长度校验示例
function validateLength(value, minLen, maxLen) {
const len = value.toString().length;
return len >= minLen && len <= maxLen;
}
// 注意:中文字符在UTF-8下占3个字节
function validateByteLength(value, maxBytes) {
const byteLen = new Blob([value]).size;
return byteLen <= maxBytes;
}
避坑指南:我曾经遇到过中文字符长度计算错误的问题。记住:中文字符在UTF-8编码下占3个字节,在GBK编码下占2个字节。金融系统通常用UTF-8,所以长度校验时要按字节算,不是按字符算。
3. 范围校验
范围校验在金融协议里特别重要。金额、利率、期限、百分比,这些都有明确的取值范围。
你想想看,如果一笔交易的金额是负数,或者利率超过100%,这明显不合理。范围校验就是要把这些「异常值」挡在门外。
我个人习惯把范围校验分成两类:
- 硬范围:协议规范里明确写死的,比如金额不能为负
- 软范围:业务逻辑决定的,比如单笔交易上限
// 范围校验示例
function validateRange(value, min, max, inclusive = true) {
if (inclusive) {
return value >= min && value <= max;
} else {
return value > min && value < max;
}
}
// 金融场景:利率校验
function validateInterestRate(rate) {
// 年化利率通常在0%到100%之间
return rate >= 0 && rate <= 1;
}
重要提醒:范围校验要注意边界值。比如「大于等于0」和「大于0」是完全不同的概念。金融系统里,0元交易是否允许?这得看具体业务场景。
4. 必填项校验
必填项校验看起来最简单,但出问题最多。为什么?因为「必填」的定义在不同场景下不一样。
我记得有一次做跨境支付系统,某个字段在境内交易是选填,在境外交易是必填。结果测试没覆盖到境外场景,上线后境外交易全部失败。
必填项校验的几个关键点:
- 空值判断:null、undefined、空字符串都要考虑
- 条件必填:某些字段在特定条件下才必填
- 默认值:有些字段可以给默认值,避免必填冲突
// 必填项校验
function validateRequired(value, fieldName) {
if (value === null || value === undefined) {
throw new Error(`${fieldName} 是必填项`);
}
if (typeof value === 'string' && value.trim() === '') {
throw new Error(`${fieldName} 不能为空字符串`);
}
return true;
}
// 条件必填示例
function validateConditionalRequired(value, condition, fieldName) {
if (condition && (value === null || value === undefined)) {
throw new Error(`当条件满足时,${fieldName} 是必填项`);
}
}
经验之谈:我建议在协议设计阶段就明确每个字段的「必填条件」。别等到开发阶段再补,那时候容易遗漏。
5. 格式校验(正则表达式)
格式校验是数据校验的「终极武器」。正则表达式虽然看着吓人,但用好了特别强大。
金融协议里常见的格式校验场景:
- 银行卡号:16-19位数字
- 身份证号:18位数字+字母X
- 手机号:1开头的11位数字
- 邮箱:标准邮箱格式
- 交易流水号:字母+数字组合
// 常用正则表达式
const patterns = {
bankCard: /^\d{16,19}$/,
idCard: /^\d{17}[\dXx]$/,
phone: /^1[3-9]\d{9}$/,
email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
transactionId: /^[A-Za-z0-9]{8,32}$/
};
function validateFormat(value, pattern) {
return pattern.test(value);
}
避坑指南:我曾经写过一个身份证号的正则,没考虑最后一位可能是X(大写或小写)。结果某个用户传了小写x,校验通过,但后端系统只认大写X。嗯,这种细节问题最容易坑人。
知识体系总览
下面这张图是我梳理的数据校验知识体系,你可以看到这五个校验维度之间的关系:
这张图展示了五个校验维度的关系。我个人习惯按照「类型→必填→长度→格式→范围」的顺序来做校验。为什么?因为类型校验最快,能过滤掉大部分明显错误。必填项校验次之,然后是长度和格式,最后才是范围校验。这个顺序能最大化校验效率。
核心总结:数据校验不是简单的「检查一下」,而是需要系统化设计的工程实践。五个维度缺一不可,顺序也有讲究。我在金融系统里见过太多因为校验顺序不对导致的性能问题,所以这个顺序是我踩坑踩出来的经验。
公众号:蓝海资料掘金营,微信deep3321