字段存在却仍然报空值:把数据标准落成 JSON Schema 契约

举报
luckyz 发表于 2026/11/12 09:02:59 2026/11/12
【摘要】 某制造企业接入设备台账,接口文档写着“设备编码必填,安装位置可空”。上线后,下游却同时收到字段缺失、显式 null 和空字符串。三种输入进入同一清洗分支,最后都变成“未知”,无法判断究竟是设备尚未安装,还是采集程序漏传字段。这个场景中的数据均为构造样例,问题来自契约没有区分存在性与取值范围。 先把争议变成四条样本我会先要求生产方和消费方共同确认四条输入的预期,而不是继续修改文字说明。设备编码...

某制造企业接入设备台账,接口文档写着“设备编码必填,安装位置可空”。上线后,下游却同时收到字段缺失、显式 null 和空字符串。三种输入进入同一清洗分支,最后都变成“未知”,无法判断究竟是设备尚未安装,还是采集程序漏传字段。这个场景中的数据均为构造样例,问题来自契约没有区分存在性与取值范围。

先把争议变成四条样本

我会先要求生产方和消费方共同确认四条输入的预期,而不是继续修改文字说明。设备编码缺失应拒绝,编码为空字符串应拒绝;安装位置允许显式 null,但字段本身必须出现。这让“尚未采集位置”和“接口没有实现位置字段”成为两种可观察状态。

JSON Schema 的 properties 用于描述字段,单独声明它不会要求字段出现;required 检查字段存在,却不会自动禁止 null。是否允许 null 要由字段的 type 决定。这个区分可在官方对象类型说明核实。本文采用 Draft 2020-12,避免校验器自行选择其他草案。

用一段程序固定语义

下面示例适用于 Python 3 和 jsonschema 4.x。保存为 contract_check.py,安装依赖后执行即可。它同时校验契约自身与输入,输出的布尔值依次为真、假、假、假。

python -m pip install 'jsonschema>=4,<5'
python contract_check.py
from jsonschema import Draft202012Validator

schema = {
    "$schema": "hxxps://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
        "device_code": {"type": "string", "minLength": 1},
        "install_location": {"type": ["string", "null"]},
    },
    "required": ["device_code", "install_location"],
    "additionalProperties": False,
}
Draft202012Validator.check_schema(schema)
validator = Draft202012Validator(schema)
samples = [
    {"device_code": "D001", "install_location": None},
    {"device_code": "D001"},
    {"device_code": "", "install_location": None},
    {"device_code": "D001", "install_location": None,
     "install_locaton": "A区"},
]
for index, sample in enumerate(samples, 1):
    errors = list(validator.iter_errors(sample))
    print(index, not errors)
    for error in errors:
        print(list(error.path), error.validator, error.message)

check_schema 与 iter_errors 的接口来自校验器官方文档。前者应在加载规则时调用;后者可以收集一条记录的多个错误,便于集中反馈。不要在错误信息中直接拼接完整原始报文,否则设备位置等字段也会进入公共日志。

空字符串和纯空白还差一步

minLength: 1 能拒绝空字符串,但不能拒绝只有空格的编码。这里必须先决定编码的标准化责任:如果允许清洗,先去除首尾空白,再校验,并保留原值与处理结果;如果禁止清洗,就把纯空白作为拒绝条件。不要让各接入任务分别决定,否则同一个编码可能在两个主题域得到不同主键。

本例故意不自动填充安装位置。把缺失字段补成 null 会抹掉契约违约证据,也使后续无法计算“字段是否按约定传输”的指标。实际落地时,我会把缺失率、显式空值率、非法类型率拆开统计,并以生产方版本和采集批次为维度观察。

严格字段集合怎样发布

additionalProperties: false 会拒绝未声明字段,这能发现样例中的拼写错误,但也意味着新增字段不能随意提前上线。它适合字段集合已经协商一致的入口;如果生产方允许独立扩展,应设计扩展对象或新的契约版本,而不是在故障时临时关闭所有检查。

建议把契约文件与正反例一起进入代码评审。一次字段调整至少回答三个问题:旧数据能否通过新规则,新数据能否被旧消费者接受,失败记录由谁处理。把位置字段从允许 null 改成只允许字符串,即使字段名称完全不变,也会改变已有输入的合法性。

验收不只看合法样本通过。必须把缺字段、空字符串、错误类型与拼写错误分别送入测试入口,确认失败原因能回到对应规则,同时确认隔离区保留了可追踪的批次编号。这样才能证明契约真正执行,而非只是保存了一份 JSON 文件。

规则失败之后怎样闭环

隔离记录需要保存规则版本和失败路径,但不必把全部字段复制到告警通知中。值班人员先按批次看失败类别,再由具备权限的处理程序定位原始输入。这样既能追查漏传,也能避免排障日志变成第二份业务数据库。

当生产方修复后,重放必须继续使用原批次对应的契约,或者明确登记规则迁移。否则同一份历史输入今天失败、明天通过,平台却无法解释变化来自数据修复还是规则放宽。每次规则发布都附上正反样本,可以把这种差异提前暴露在评审阶段。

小结

必填与非空是两条独立约束。先明确缺失、null、空字符串的业务含义,再把存在性、类型与字段集合写入可执行契约,数据标准才能在接口变更时提供明确、可回归的判断依据。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。