2 分钟

道格拉斯·克罗克福德与 JSON:为什么每个应用都使用它

讲述道格拉斯·克罗克福德如何推广 JSON,以及它为何成为 Web 应用和 API 的默认数据格式,并提供今天有效使用 JSON 的实用建议。

道格拉斯·克罗克福德与 JSON:为什么每个应用都使用它

JSON 用通俗的话说:它是什么,为什么重要

JSON (JavaScript Object Notation) 是一种用简洁文本表示数据的轻量方式,使用键–值对和列表。

如果你在构建 Web 应用——即使你不怎么考虑“数据格式”——JSON 很可能已经是把产品连接在一起的粘合剂。它是前端请求数据的方式、后端响应的方式、移动应用同步状态的方式,以及第三方服务发送事件的方式。当 JSON 清晰且一致时,团队交付更快;当它混乱时,每个功能都需要更久,因为大家在争论数据“是什么意思”。

一个小示例

下面是一个可以一目了然的小 JSON 对象:

{
  "userId": 42,
  "name": "Sam",
  "isPro": true,
  "tags": ["beta", "newsletter"]
}

即使没有技术背景,你通常也能推断出正在发生的事:一个用户有 ID、姓名、状态标志和标签列表。

你将从本文获得的内容

你将了解:

  • JSON 的来源以及它如何成为主流(包括道格拉斯·克罗克福德的角色)
  • 它“极简”设计为何成为制胜关键
  • 为何 JSON 与 API 和 HTTP 天然契合
  • 关于如何正确使用 JSON 的实用建议——以便随着应用增长,负载仍保持可读与可维护

目标很简单:帮助你理解不仅仅是 JSON 是什么,还有为什么几乎每个应用都“会说”它——以及如何避免团队反复犯的常见错误。

道格拉斯·克罗克福德在推动 JSON 成为主流中的角色

道格拉斯·克罗克福德并没有把 JSON 的每个概念都“发明”出来,但他做了一件同等重要的事:把一个简单且可行的模式公开、命名它,并推动其进入主流。

早期 Web 的问题:数据交换很混乱

在 Web 应用的早期,团队在浏览器与服务器间移动数据时,要在各种尴尬的选项间抉择。XML 很常见,但冗长;基于自定义分隔符的格式紧凑但脆弱;JavaScript 技术上可以把数据当作代码来求值,但那模糊了“数据”和“可执行脚本”之间的界限,容易引发 bug 与安全问题。

克罗克福德看到了更清晰的路径:使用 JavaScript 字面量语法的一个小子集来可靠地表示纯数据——对象、数组、字符串、数字、布尔与 null——而去掉多余特性。

命名、文档与“能指向的那一页”

克罗克福德最大的贡献之一是社会性的而非纯技术性的:他给它命名为 JSON(JavaScript Object Notation),并在 json.org 发布了清晰文档。这为团队提供了共同的词汇(“我们会发送 JSON”)和一个既短又足够严格以供实现的参考页面。

他还推广把 JSON 视为独立于 JavaScript 的数据格式:很多语言都能解析与生成它,并且它自然映射到常见的数据结构。

让人放心的标准化里程碑

当团队觉得可以长期押注某个格式时,采用会加速。JSON 通过一些广为人知的里程碑逐步获得这种“可靠赌注”地位:

  • RFC 4627 (2006):早期的互操作性说明
  • ECMA-404:定义 JSON 语法的简明标准
  • RFC 7159 以及后来的 RFC 8259 (2017):澄清互操作性并巩固 JSON 在互联网上的地位

克罗克福德的推动,加上这些标准和日渐丰厚的解析器生态,帮助 JSON 从一种方便的约定变成了应用之间通信的默认方式——尤其是在 HTTP API 之间(后文并在 /blog/json-and-apis 有更多介绍)。

在 JSON 之前:Web 曾使用的数据格式

在 JSON 成为默认传输方式之前,Web 依赖的是一组要么过于沉重、要么不一致、要么高度定制的格式,难以在团队间扩展。

早期常见的选择

XML 是主要的“标准”选择:跨语言、工具成熟、能表示嵌套结构,但带来很多样板。

同时,许多应用把数据当作 自定义查询字符串 传递(尤其在早期 AJAX 请求中):键/值塞进 URL 或 POST 正文。也有应用发明了临时文本格式——此处逗号分隔、彼处管道分隔——通常伴随着只有一个开发者懂得的手工转义规则。

团队经常碰到的问题

这些问题并不是理论性的:

  • 冗长:XML 让小负载显得臃肿,数据量大时更是如此。
  • 解析复杂:真实世界的 XML 往往需要更重的解析器,并需处理命名空间、属性与元素的区分,以及空白字符问题。
  • 约定不一致:在临时格式中,每个端点都像是一个小协议。客户端不得不猜测类型、编码和边界情况。

为什么“够用且简单”会胜出

大多数应用并不需要能表达每种文档结构的格式。它们需要一种可预测的方式来快速、一致地传输对象、数组、字符串、数字与布尔值——并尽量减少可解释的空间。更简单的格式能降低每个端点需要做出的决策(以及犯错的机会)。

快速对比:XML vs JSON

\u003cuser\u003e
  \u003cid\u003e42\u003c/id\u003e
  \u003cname\u003eAda\u003c/name\u003e
  \u003cisActive\u003etrue\u003c/isActive\u003e
\u003c/user\u003e
{
  "id": 42,
  "name": "Ada",
  "isActive": true
}

两者表达同一含义,但 JSON 更易扫描、更易生成,并且更接近大多数应用在内存中对数据的建模方式。

为什么 JSON 极简:那些奏效的设计选择

JSON 能够长期存在并非偶然。它之所以成功,是因为它被刻意做得很小:仅提供足够去表示真实应用数据的结构,而不允许无限变化。

最小且实用的构建模块

JSON 提供的工具集合与大多数应用的数据观念直接对应:

  • 对象:命名字段(例如联系人有 nameemail
  • 数组:有序列表(例如购物车项)
  • 字符串:文本
  • 数字:数值(有些注意事项)
  • 布尔true / false
  • null:显式的“无值”

仅此而已。没有内建日期、没有注释、没有自定义数值类型、没有引用。正因如此,JSON 更容易在不同语言与平台间实现。

可读且对机器友好——设计如此

JSON 对人足够可读,便于在日志与 API 响应中快速浏览,同时对机器来说也易于解析。它避免了不必要的样板,但保留了清晰分隔符({}[]:),使解析器能快速且可靠地工作。

代价是:由于 JSON 极简,团队必须就时间戳、货币和标识符等约定达成一致(例如采用 ISO-8601 表示日期)。

严格性是优点,而不是限制

JSON 的严格规则(字符串必须双引号、禁止尾随逗号、类型集合固定)减少了模棱两可。更少的歧义意味着不同系统交换数据时更少出现“在我机器上能跑”的问题。

一个值得澄清的误解

JSON 看起来像 JavaScript 对象语法,但 JSON 不是 JavaScript。它是一种与语言无关的数据格式,Python、Java、Go、Ruby 等语言都能使用它进行一致的序列化与互操作。

JSON 如何成为前端与后端之间的默认契约

JSON 并非因为功能最丰富而胜出,而是因为它契合 Web 应用的构建方式:浏览器端大量使用 JavaScript,通过简单的 HTTP 请求与服务器通信。

JavaScript 已经存在于每个页面

一旦浏览器标准化使用 JavaScript,客户端就有了内建的结构化数据表示:对象、数组、字符串、数字、布尔与 null。JSON 与这些原语高度对应,因此在“浏览器能理解的东西”和“服务器发送的东西”之间传输数据显得很自然。

早期 Ajax 风格的应用加速了这一点。服务器无需返回完整的 HTML 页面,而可以返回一个小负载供 UI 渲染。例如:

{
  "user": {"id": 42, "name": "Sam"},
  "unreadCount": 3
}

到处都能轻松解析,而不仅限于浏览器

尽管 JSON 语法像 JavaScript,但它是语言中立的。只要服务器与客户端(用其它语言实现)需要与 Web 前端互操作,JSON 库就会出现并且迅速成为“标配”。把 JSON 字符串解析为本地数据结构通常只需一次函数调用,生成 JSON 也同样简单。

工具链形成默认选择的雪崩效应

当框架、API 客户端、调试器、代理与文档工具都假定使用 JSON,选择其他格式会带来摩擦。开发者可以在浏览器开发者工具中检查负载、把示例粘贴到测试中,并依赖成熟的库来编码、解码与处理错误。

一个响应,多种消费者

一份 JSON 响应可以同时服务 Web UI、移动端、内部服务与第三方集成,几乎无需改动。这种互操作性让 JSON 成为“一个后端,多前端”场景的安全选择,也促成了它作为客户端与服务器之间默认契约的地位。

JSON 与 API:它与 HTTP 的实用契合

在一次会话内快速原型
在一次对话中将数据模型变成可用端点与界面。

JSON 胜出的原因并非华丽,而是它与 Web 的工作方式无间契合。HTTP 围绕请求与响应构建,而 JSON 是表示响应(或请求)主体的轻量且可预测的数据格式。

在一分钟内理解 HTTP + JSON

一次 API 请求通常包含方法和 URL(例如 GET /users?limit=20)。服务器用状态码(如 200404)、头部与可选主体回复。

当主体是 JSON 时,一个关键头部是:

  • Content-Type: application/json

这个头告知客户端如何解释接收到的字节。在客户端→服务器 的请求中发送 Content-Type: application/json 表示“我在提交 JSON”,服务器即可一致地解析它。

常见 API 响应模式

JSON 非常适合许多 API 中反复出现的模式。

分页 通常用元数据包裹列表:

{
  "data": [{"id": 1, "name": "A"}],
  "pagination": {"limit": 20, "offset": 0, "total": 153}
}

过滤与排序 通常出现在 URL 查询串中,而结果仍是 JSON 数组或 data 字段。例如:GET /orders?status=paid\u0026sort=-created_at

错误响应 受益于统一的形状,便于客户端展示信息并处理重试:

{
  "error": {
    "code": "invalid_request",
    "message": "limit must be between 1 and 100",
    "details": {"field": "limit"}
  }
}

实务上的匹配很简单:HTTP 提供传输与语义(动词、状态码、缓存),而 JSON 提供轻量且可读的数据结构。

JSON vs XML:为什么 JSON 通常更适合应用数据

当人们把 JSON 和 XML 做比较时,实际上常是在比较“应用数据”与“文档”。两者都能表示结构化信息,但 JSON 更符合大多数应用实际在移动的数据:简单对象、列表、字符串、数字、布尔与 null。

可读性与体积:更少标签,更少噪音

XML 本就冗长。重复的开闭标签让负载更大,也更难在日志或网络检查器中浏览。JSON 通常用更少字符与更少视觉杂乱来传达相同含义,这有助于调试并在大规模下减少带宽成本。

这不仅是审美问题:更小的负载通常意味着更快传输和更少的解析与代理负担。

数据模型对齐:映射与列表更贴合应用数据

大多数应用数据天生像字典(键/值)和数组(列表):一个用户有属性、一个订单有行项、一个页面有组件。JSON 直接映射至这种心智模型,并与 JavaScript 及大多数现代语言的原生数据结构匹配。

XML 可以表示相同结构,但通常需要额外约定:属性 vs 元素、用重复子元素表示列表、以及关于“什么算数字”的额外规则(因为一切都作为文本,除非在上层加类型)。

XML 的适用场景(并非全盘否定)

XML 在文档为中心的场景中仍然很强:混合内容(文本与标记交织)、出版流程,以及某些有成熟 XML 工具链的企业生态。如果你的负载更像文档而不是对象图,XML 仍然可以是更合适的工具。

指南:基于需求选择,而不是跟风

如果你的主要目标是在前端、后端与 API 间交换应用数据,JSON 通常是更简单、更直接的选择。如果你需要文档标记、混合内容,或必须融入以 XML 为主的领域,XML 可能更合适。

仍然让团队吃惊的 JSON 规则

用真实流量测试
部署你的应用,尽早验证真实请求与响应的 JSON。

JSON 看起来像“JavaScript 对象”,因此团队常常把它当作 JavaScript 来处理。这正是 bug 的来源之一:JSON 更严格、更精简、更不容忽视细节。

严格的语法规则

一些“在我机器上能跑”的问题反复出现:

  • 键与字符串必须使用双引号。 {name: "Ada"} 不是 JSON;{ "name": "Ada" } 才是。
  • 禁止尾随逗号。 { "a": 1, } 在许多解析器中会失败。
  • 不允许注释。 ///* ... */ 都是无效的。如果需要注释,请写在文档中或在开发阶段用单独字段(谨慎)记录。

这些约束是有意为之:它们让解析器简单且在各语言间表现一致。

数字、日期与小数:要有意识地选择类型

JSON 只有一种数字类型:number。没有内建的整数、十进制或日期类型。

  • 货币与高精度小数(价格、汇率)通常更安全地作为字符串发送(例如 "19.99"),以避免跨系统的舍入差异。
  • 日期与时间 通常应作为字符串并使用标准格式,最常见的是 ISO 8601(例如 "2025-12-26T10:15:30Z")。避免使用需要额外猜测的自定义日期格式。
  • 小心非常大的整数:某些环境无法精确表示它们。存疑时,请以字符串形式传输。

Unicode 与字符串转义在真实系统中的问题

JSON 支持 Unicode,但真实系统在编码与转义上仍会出错:

  • 确保传输中全部使用 UTF-8
  • 记住字符串内必须转义某些字符(如引号 " 与反斜杠 \)。
  • 小心从文档复制过来的不可见字符(不间断空格、智能引号)会导致解析失败。

安全:安全地解析 JSON

始终使用真实的 JSON 解析器(JSON.parse 或你所用语言的等价函数)来解析 JSON。避免任何 eval 风格的方法,即使看起来“更快”。并在边界处验证输入——尤其是公共 API——以防意外字段或类型渗入业务逻辑。

设计能够经受时间考验的 JSON 负载

JSON 负载不仅仅是“在路上的数据”——它是团队、系统与未来的你之间的长期接口。能够长期使用的负载与每个季度都要重写的负载之间的差别,通常来自枯燥但必要的纪律:一致性、谨慎的变更管理与对边界情况的明确约定。

一致性胜过聪明

选择一种命名规则并始终如一地使用它:

  • 采用一种命名风格(常见 camelCasesnake_case)并避免混用。
  • 保持键的稳定。把 userId 重命名为 id 是破坏性变更,即使语义看似明显。
  • 偏好显式字段而不是“魔法”多态。键的类型发生变化("count": 3 vs "count": "3")会导致难以追踪的 bug。

无戏剧的版本管理

通过采用增量变化可以避免大多数版本纠纷:

  • 添加新的可选字段,而不是更改或删除现有字段。
  • 把删除作为弃用:保留旧字段,不在新客户端中文档化,并公告移除日期。
  • 若确需破坏性变更,版本化端点(/v2/...)或在头部加入明确版本信号——不要悄然改变语义。

错误应当平淡且可预测

当错误具有统一形状时,客户端更容易处理失败:

{
  "error": {
    "code": "INVALID_ARGUMENT",
    "message": "email must be a valid address",
    "details": { "field": "email" }
  }
}

与真实行为一致的文档

优秀的 JSON 文档包含真实示例——成功与失败的响应都要包含完整字段。保持示例与生产行为同步,并标注哪些字段是可选、可为 null 或已弃用。当示例与真实响应一致时,集成更快、更少出错。

Koder.ai 在何处契合(如果你快速构建 API)

如果你使用一种快速编码的工作流快速推出功能,JSON 契约变得更加重要:快速迭代很好,但直到客户端和服务发生漂移才发现问题。

Koder.ai 上,团队通常生成 React 前端和 Go + PostgreSQL 后端,然后在 planning mode 中先迭代 API 形状再锁定。像 snapshots 和 rollback 的功能在“一个小”JSON 变更变成破坏性变更时很有用,源代码导出 则便于把契约放入仓库并用测试强制执行它们。

验证与契约:JSON Schema 以及更多

JSON 很容易生成,这既是优点也是陷阱。如果一个服务发送 "age": "27"(字符串)而另一个期待 27(数字),JSON 本身不会阻止这种不匹配。结果往往是最糟糕的那类 bug:生产环境中客户端崩溃,或只有在特定数据下才出现的微妙 UI 问题。

为什么验证重要(即便是“简单”的 JSON)

验证是为了在坏数据或意外数据到达依赖它的系统之前捕获问题——无论是前端、合作伙伴集成、分析管道还是移动端应用。

常见失败点包括缺失必需字段、键被重命名、类型错误以及“几乎正确”的值(比如不一致的日期格式)。在 API 边界做一步小小的验证,可以把这些问题从宕机变成明确的错误信息。

JSON Schema 是什么、何时使用

JSON Schema 是描述 JSON 应有结构的标准方式:必需属性、允许的类型、枚举、模式等。它在以下场景最有用:

  • 你有多个客户端(Web + 移动 + 合作伙伴)消费同一 API
  • 你需要随时间进行向后兼容的变更
  • 你希望在 CI/CD 中进行自动化检查,而不仅仅依赖人工审阅

有了 schema,你可以在服务器端验证请求、在测试中验证响应并生成文档。很多团队把它与 API 文档(通常通过 OpenAPI)配对,使契约显式而非“部落知识”。如果你已有开发者文档,可以在 /docs 链接 schema 示例以保持一致性。

轻量替代与补充方案

并非每个团队在第一天就需要完整的 schema 工具链。实用选项包括:

  • 存在仓库中的共享示例负载(golden files)
  • 契约测试,验证真实响应是否符合预期
  • 消费方驱动的契约(由客户端定义所需内容)

一个有用的规则是:从示例与契约测试开始;当变更与集成增多时再引入 JSON Schema。

在大规模下用好 JSON 的性能与可靠性

生成 Go JSON API
通过对话定义端点,生成可扩展的 Go + PostgreSQL 后端。

当你只发送几字段时,JSON 感觉“轻量”。在大规模场景下——移动客户端在不稳定网络、高流量 API、分析密集页面——如果不谨慎塑形与传输,JSON 可能成为性能或可靠性瓶颈。

保持负载小:分页、过滤并避免过度抓取

最常见的扩展性问题不是解析,而是传输了过多数据。

分页是简单的胜利:返回可预测的块(例如 limit + cursor),防止客户端一次下载数千条记录。对于返回嵌套对象的端点,考虑部分响应:让客户端只请求所需字段(所选字段或 "include" 展开)。这能阻止“过度抓取”,即界面只需 namestatus,却收到所有历史和配置字段。

一个实用规则:围绕用户动作设计响应(屏幕“现在”需要什么),而不是围绕数据库如何 join。

压缩与缓存:更少字节,更少请求

如果你的 API 返回较大的 JSON,启用压缩能显著减少传输大小。许多服务器可自动做 gzip 或 brotli 压缩,而大多数客户端无需额外代码即可处理。

缓存是另一个重要手段。总体目标是:

  • 对不频繁变化的数据使用可缓存的响应
  • 明确缓存策略(例如使用 ETag 或“last modified”模式)

这能减少重复下载并缓解流量峰值。

当 JSON 很大时的流式与增量解析

对于非常大的输出——导出、事件流、批量同步——考虑流式响应或增量解析,让客户端不必先把整个文档加载到内存才能开始有用的处理。这对大多数应用不是必需的,但当“一个大 JSON blob”开始超时时,这是有价值的选项。

可观测性:安全记录并避免泄露

JSON 易于记录,这既有利也有风险。把日志当作产品接口来处理:

  • 默认不要记录整个请求/响应体
  • 对敏感字段脱敏(token、密码、个人标识)
  • 偏好结构化日志,记录 ID、时延与错误码,而不是原始负载

做好这些,你会更快地排查问题,同时降低意外数据泄露的风险。

JSON 的下一步与简明最佳实践清单

JSON 不是“完结”的规范——它是稳定的。现在变化的是围绕它的生态:更强的编辑器、更好的验证、更安全的 API 契约以及帮助团队避免意外破坏性改动的工具链。

JSON 的未来走向

JSON 很可能继续作为大多数 Web 与移动应用的默认线格式,因为它被广泛支持、易于调试并且与常见数据结构清晰映射。

最大的变化是走向“类型化 API”:团队仍然发送 JSON,但会用 JSON Schema、OpenAPI 和代码生成器等工具更精确地定义它。这意味着更少的“猜测形状”时刻、更好的自动补全与更早的错误发现——而不会放弃 JSON 本身。

相关格式:JSON Lines / NDJSON

当你需要高效地发送或存储大量记录(日志、分析事件、导出)时,一个巨大的 JSON 数组会显得笨重。JSON Lines(也称 NDJSON)通过“每行一个 JSON 对象”解决这个问题。它易于流式处理、可逐行消费,并且与命令行工具兼容良好。

一个简易的最佳实践清单

在发布长期存在的负载前,作为快速检查表使用:

  • 保持键一致且可预测(选择一种命名风格并坚持)。
  • 偏好稳定标识符(不要让客户端依赖数组位置)。
  • 使用 ISO 8601 时间戳(例如 2025-12-26T10:15:00Z)。
  • 区分“缺失” vs “空” vs null 并在文档中说明你的选择。
  • 谨慎版本化(自由添加字段;删除/重命名需有计划)。
  • 在边界处进行验证(服务器端输入验证;客户端做合理性检查)。
  • 返回有用的错误(机器可读的代码 + 人类可读文本)。

持续学习

如果想深入,可在 /blog 浏览相关指南——特别是关于 schema 验证、API 版本化以及为长期兼容性设计负载的主题。

常见问题

简单来说,JSON 是什么?

JSON 是一种用于传输结构化数据的纯文本格式。它使用带名称字段的对象、数组、字符串、数字、布尔值和 null。

Douglas Crockford 为 JSON 做了什么?

Douglas Crockford 为 JSON 命名,清晰地记录了它,并将其推广为一种可供多种编程语言使用的小型数据格式。他帮助把一种实用的约定变成了共享标准。

为什么 JSON 如此常见?

JSON 之所以普及,是因为它紧凑、易读,浏览器和服务器也很容易解析。它的结构还与应用程序已经使用的对象和数组非常接近。

JSON 如何与 API 配合使用?

API 通常会在请求体或响应体中发送 JSON。HTTP 负责请求、状态码和标头,而 JSON 描述数据本身。

Content-Type application/json 是什么意思?

当 HTTP 请求体或响应体包含 JSON 时,发送标头 Content-Type: application/json。它会告诉接收系统如何解析请求体或响应体。

我应该在什么时候使用 JSON 而不是 XML?

大多数应用数据都适合使用 JSON,例如用户、订单、设置和 API 响应。当你需要文档式标记、文本与标签混合的内容,或必须对接基于 XML 的集成时,请选择 XML。

JSON 和 JavaScript 对象一样吗?

不一样。JSON 要求字段名称和文本值使用双引号,不允许注释,也不接受末尾逗号。JavaScript 对象可以使用不符合有效 JSON 的语法。

我应该如何在 JSON 中存储日期和金额?

时间戳应使用字符串存储,通常采用 ISO 8601 格式。精度很重要时,应将金额和非常大的整数 ID 存为字符串,因为 JSON 只有一种数字类型。

如何设计不会在以后破坏客户端的 JSON?

选择一种命名风格,保持字段类型稳定,并通过添加可选字段来扩展,而不是重命名或删除已有字段。错误信息应采用统一的结构,这样每个客户端都能以同样的方式处理它们。

如何安全地处理 JSON?

使用 JSON 解析器,并在应用程序使用传入数据前验证它。不要使用 eval,并避免记录可能包含密码、令牌或个人数据的完整负载。

Related posts