JSON 工具箱

draft-07 和 2020-12 该用哪个

结论:2020-12 是当前推荐版本,`$defs`、`prefixItems`、`unevaluatedProperties` 都在这里;但很多老校验器、代码生成器仍只认 draft-07。选版本的依据不是新旧,而是「链路上每个工具都支持哪个」。

深入约 4 分钟发布于 2026-10-30更新于 2026-10-30
JSON Schema 各版本的差异与选型建议

结论:新项目直接用 2020-12,只要校验器、代码生成器或 OpenAPI 工具链中有组件只认 draft-07,就退回 draft-07,并在文件里写死 $schema。

一句话:新项目用 2020-12,链路上有老组件就退 draft-07。

版本演进速览

版本 年份 关键变化
draft-04 2013 早期广泛使用,id 而非 $id
draft-06 2017 加 const、propertyNames
draft-07 2018 加 if/then/else、readOnly、contentMediaType,目前兼容性最好
2019-09 2019 $defs 取代 definitions,加 unevaluatedProperties
2020-12 2020 prefixItems 取代数组元组写法,$dynamicRef,当前推荐版本

2020-12 好用的地方

数组元组写法统一了。 draft-07 里用 items: [{...}, {...}] 表示「第一个元素是 A、第二个是 B」,additionalItems 控制后续;2020-12 改成 prefixItems + items,语义清晰得多,也不会和「所有元素都是同一结构」的写法混淆。

$defs 更规范。 虽然 draft-07 的 definitions 也能用,但 2019-09 之后官方统一为 $defs,新工具默认按这个找。

unevaluatedProperties 解决组合难题。 用 allOf 组合多个 Schema 时,additionalProperties: false 会误杀其他分支定义的字段;unevaluatedProperties: false 只看「最终求值过的属性」,这才是组合场景想要的行为。

什么时候必须退回 draft-07

情况 原因
使用 OpenAPI 3.0 规范内置的就是 draft-04/07 的子集
校验器是老版本(ajv 6、部分 Java 库) 不认识 prefixItems、$dynamicRef
平台方指定 Schema 版本 比如某些低代码平台、API 网关
需要生成代码的工具只支持到 07 生成器会静默忽略不认识的关关键字

判断方法很直接:拿一段用 prefixItems 的 Schema 丢进你的校验器,如果它不报「未知关键字」而是直接通过校验,说明它在静默忽略——这比报错更危险。

混用时的注意事项

永远写 $schema。 不写时不同库的默认版本不一样,ajv 默认 draft-07,部分 Python 库默认 2020-12。同一个文件在两处校验结果不同,排查起来非常费劲。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/schemas/order.json",
  "type": "object"
}

别跨版本引用。 $ref 指向另一个版本的 Schema,行为未定义,多数实现会按当前版本解释,$defs 与 definitions 混着写必然出问题。

升级要成批做。 一个项目里同时存在两种版本的 Schema,等于把「这份文件到底按哪个版本解释」变成人工记忆,早晚出错。

常见问题

如何判断校验器是否真的支持 2020-12?

拿一段使用 prefixItems 的 Schema 丢进校验器:报「未知关键字」说明不支持,直接通过校验则说明它在静默忽略,这比报错更危险。

为什么要让整个项目统一版本?

一个项目同时存在两种版本,等于把「这份文件按哪个版本解释」变成人工记忆,早晚出错。升级应当成批完成。

是否可以不写 $schema?

不建议。不写时不同库的默认版本不一样,ajv 默认 draft-07,部分 Python 库默认 2020-12,同一个文件在两处校验结果可能不同。

相关工具

延伸阅读