数据校验基础:字段类型、长度、范围、必填项与格式校验

数据校验这事儿,说白了就是给金融协议做「体检」。我做了这么多年金融系统,见过太多因为校验不到位导致的线上事故。有一次凌晨三点被叫起来,就因为一个金额字段传了字符串,结果清算系统直接崩了。嗯,从那以后我对数据校验就特别较真。

今天咱们就把数据校验的五个基本功掰开揉碎讲清楚。你想想看,金融协议里每一笔交易都是真金白银,校验做不好,后果很严重。

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