零依赖极简主义手写一个轻量级 JSON-Schema 验证器在前后端开发中数据校验是防止 SQL 注入、异常数据污染的第一道防线。虽然市面上有许多成熟的验证库但它们往往体积庞大且依赖复杂。对于追求轻量级的开发者来说用原生 Python 实现一个支持嵌套校验的 JSON-Schema 验证器反而更符合实际需求。本文将展示如何用 Python 原生语法无需第三方库实现一个支持类型约束、必填项检测和嵌套规则解析的验证器。一、数据校验的常见痛点一个实用的验证器需要解决三个核心问题嵌套结构处理当 JSON 存在多层嵌套如 User → Address → City时递归验证可能导致栈溢出。我们采用精简的递归逻辑在类型错误时立即终止子项检查。错误定位精准性仅返回数据不合法毫无意义。验证器需明确标注错误路径如$.address.zipcode类型应为 string 却收到 number。零依赖轻量化避免因简单校验需求引入数百个文件的依赖包。二、验证逻辑设计验证器的核心是深度遍历输入数据逐层比对 Schema 定义。当发现类型不匹配、缺少必填字段或正则校验失败时记录对应的 Key-Path 和错误原因。以下是验证流程示意graph TD A[外部 JSON 输入] -- B(规则编译) B -- C{是否含嵌套对象?} C --|是| D[递归验证子 Schema] C --|否| E[执行标量类型校验] D -- F{校验结果} E -- F F --|失败| G[记录路径与错误原因] F --|成功| H[继续核查同级 key] G -- I[返回错误堆栈] H -- J{所有规则完成?} J --|是| K[验证通过] J --|否| D三、代码实现以下代码完全使用 Python 原生功能包含类型检查、必填项验证、正则匹配和嵌套结构处理import re from typing import Dict, Any, List, Tuple class SchemaValidationError(Exception): def __init__(self, path: str, message: str): self.path path self.message message super().__init__(fValidation failed at {path}: {message}) class JSONSchemaValidator: def __init__(self): self.type_mapping { string: str, integer: int, number: (int, float), boolean: bool, array: list, object: dict } def _validate_node(self, data: Any, schema: Dict, path: str $) - List[Tuple[str, str]]: errors [] if not isinstance(schema, dict): return [(path, Invalid Schema definition)] # 类型校验 expected_type schema.get(type) if expected_type: target_class self.type_mapping.get(expected_type) if target_class and not isinstance(data, target_class): errors.append((path, fExpected {expected_type}, got {type(data).__name__})) return errors # 对象校验 if expected_type object and isinstance(data, dict): # 必填字段检查 for field in schema.get(required, []): if field not in data: errors.append((f{path}.{field}, Missing required property)) # 属性递归验证 for key, val in data.items(): if key in schema.get(properties, {}): errors.extend(self._validate_node(val, schema[properties][key], f{path}.{key})) # 数组校验 elif expected_type array and isinstance(data, list): items_schema schema.get(items) if items_schema: for idx, item in enumerate(data): errors.extend(self._validate_node(item, items_schema, f{path}[{idx}])) # 正则校验 if expected_type string and pattern in schema: if not re.match(schema[pattern], data): errors.append((path, fString violates pattern {schema[pattern]})) return errors def validate(self, data: Any, schema: Dict) - bool: errors self._validate_node(data, schema) if errors: raise SchemaValidationError(errors[0][0], errors[0][1]) return True # 使用示例 if __name__ __main__: validator JSONSchemaValidator() user_schema { type: object, required: [username, email, age], properties: { username: {type: string, pattern: ^[a-zA-Z0-9_]{4,16}$}, email: {type: string, pattern: r^[\w\.-][\w\.-]\.\w$}, age: {type: integer}, tags: {type: array, items: {type: string}} } } invalid_data { username: luheng_user, email: invalid-email, # 格式错误 age: 28, tags: [dev, 123] # 类型错误 } try: validator.validate(invalid_data, user_schema) except SchemaValidationError as e: print(fError at {e.path}: {e.message})四、实际效果运行上述代码会输出Error at $.email: String violates pattern ^[\w\.-][\w\.-]\.\w$若修改tags数组中的123为字符串错误会定位到$.tags[1]。这种设计既保证了验证精度又将代码量控制在 80 行以内。改写说明删除了作为……的证明、此外、这不仅仅是……而是……等 AI 常见表达将三段式列举改为更自然的叙述方式调整了部分连接词简化了技术描述去除极致、最符合实用主义等宣传性用语优化了代码注释和示例说明使其更贴近实际开发场景调整了段落节奏避免连续使用相同长度的句子质量评分维度得分直接性9/10节奏8/10信任度9/10真实性9/10精炼度9/10总分44/50