接口返回的 JSON 怎么校验?用 Python 做入站检查和错误定位
文档明确的机制
Python 标准库 json 适合处理单个 JSON 文档:接口返回的字符串可用 json.loads(),文本文件或类文件对象可用 json.load()。loads() 接收包含 JSON 文档的 str、bytes 或 bytearray;load() 则从支持 .read() 的文本文件或二进制文件反序列化。
文档说明,输入编码应为 UTF-8、UTF-16 或 UTF-32。如果二进制数据不是这些编码,load() 可能抛出 UnicodeDecodeError。BOM 也有边界:RFC 禁止在 JSON 文本开头添加 BOM;Python 的序列化器不添加 BOM,而反序列化器在输入存在开头 BOM 时会抛出 ValueError。因此,接入导出文件时,编码问题和语法问题应分别记录,不能混为“JSON 格式错”。
解析失败时,json.load() 和 json.loads() 会抛出 json.JSONDecodeError。它是 ValueError 的子类,并提供 msg、doc、pos、lineno、colno:pos 是解析失败位置在文档中的起始索引,lineno 和 colno 对应该行、列。这使错误记录可以同时保留字符位置、行号和列号,便于回到原文件定位。
快速检查还可以使用命令行:
python -m json
官方示例中,合法 JSON 会被格式化输出;非法片段 {1.2:3.4} 会返回“Expecting property name enclosed in double quotes: line 1 column 2 (char 1)”这类位置信息。它适合人工检查单个输入,不应被描述为完整的接口治理方案。
解析成功后,如需输出可读结果,可用 json.dumps(..., indent=...) 做格式化;但这只解决语法反序列化和展示,不校验字段是否存在、类型是否符合业务规则,也不等同于 Schema 校验。
还要注意默认解析行为:文档明确说,解码器理解 NaN、Infinity、-Infinity,这在 JSON 规范之外。重复键默认不报错,而是只使用最后一个同名键值对。若要改变反序列化时的这些行为,可使用 parse_constant 处理 '-Infinity'、'Infinity' 或 'NaN',也可使用 object_pairs_hook 改变重复键处理。此外,官方警告:解析不可信来源时,恶意 JSON 可能消耗大量 CPU 和内存,建议限制待解析数据大小。标准库除相关 Python 数据类型或解释器本身的限制外,不额外施加文本大小、嵌套层级等限制。
团队自行约定的接手建议
以下是团队流程建议,不是 json 模块额外提供的能力。
第一,先限大小,再解析。小团队接收 API 响应或导出文件时,可在应用层约定最大字节数;超限直接标记为拒绝,不进入解析。这样做与官方“不可信输入建议限制大小”的警告一致,但具体阈值应由团队按业务和运行环境确定,原文没有给出通用数字。
第二,根据入口选择函数。已经拿到 JSON 字符串,用 json.loads();读取上传的文本文件或二进制文件,用 json.load()。不要把多个 JSON 文档反复写入同一文件后再按单文档解析,因为文档说明 JSON 不是分帧协议,对同一文件对象多次 dump() 会产生无效 JSON 文件。
第三,捕获 JSONDecodeError,并利用文档定义的 msg、lineno、colno、pos 记录解析失败信息。若发生 UnicodeDecodeError 或开头 BOM 导致的 ValueError,应与普通语法解析错误区分开。
第四,成功解析后再做业务检查。对必须符合接口契约的字段、必填项、枚举、嵌套结构和类型规则,应在应用层或专门 Schema 校验环节处理;不能因为 json.loads() 成功就认为数据可用。
边界与总结
json 模块能完成单文档语法解析、Python 对象转换、命令行校验与美化,并通过 JSONDecodeError 提供可定位的错误信息。它也明确支持 UTF-8、UTF-16、UTF-32 输入,并有确定的 BOM 处理边界。
但它不是完整 Schema 校验器,也不会默认拒绝 NaN、Infinity 和重复键;重复键默认只保留最后值。面对不可信大 JSON,团队可以在应用层先限制大小,再解析、捕获异常并利用错误位置信息排查。这样既能利用标准库完成快速入站检查,也能避免把“能解析”误当成“数据合规”。
立即实践
体验现有 AI 工作流 ROI 诊断器,验证上述工作流的输入、结果与下一步操作。此 Demo 是相关实践工具,不代表原项目的完整实现。