跳到主内容
d.devtul.fun
数据格式 · 2026-09-15

JSON 和 YAML,什么时候该用哪个

把同一份配置用两种格式写出来,差别一目了然:

{
  "name": "devtul",
  "port": 8080,
  "features": ["json", "yaml"],
  "database": { "host": "localhost", "ssl": true }
}
name: devtul
port: 8080
features:
  - json
  - yaml
database:
  host: localhost
  ssl: true

YAML 少了引号、少了逗号、少了括号,代价是对缩进极度敏感。

JSON 的优势

  • 没有歧义。格式规则简单到可以用几百字写完,任何语言的标准库都能解析,不存在"这个解析器行为不一样"的问题。
  • 容错性好。压缩成一行、换行、加不加空格,都不影响结果。用版本控制时冲突也容易看清。
  • 解析快。几乎每种语言都有原生加速实现。

缺点是:写的时候啰嗦,不能写注释,多行字符串很难处理。

YAML 的优势

  • 读起来干净。层级深的配置,YAML 的扫描速度明显更快。
  • 支持注释。这对配置文件的维护性影响很大 —— 半年后回来改,能看懂当初为什么这么写。
  • 多行字符串。用 | 可以保留换行,用 > 可以折叠换行,写脚本或者证书内容时非常方便。
  • 支持锚点与引用。用 &name 定义、*name 引用,可以避免重复的配置块。

YAML 的坑

YAML 的表达能力是它的优势,也是它的问题来源。

一、缩进错了就是语法错

用空格还是 Tab,缩进几格,都必须全局一致。编辑器把 Tab 显示成 4 格但实际存了 \t,就会出现"看起来对齐、解析却报错"的情况。

二、隐式类型转换

这一条杀伤力最大:

country: NO     # 不是字符串 "NO",而是布尔值 false
version: 1.20   # 不是字符串 "1.20",而是数字 1.2
time: 12:30     # 会被解析成 750(六十进制)
yes_no: yes     # 布尔值 true

挪威的区号、软件版本号、时间字符串 —— 这些一旦不加引号,就会被静默地转成别的类型。解决办法就是拿不准就加引号。

三、解析器行为不完全统一

YAML 规范相当庞大,不同语言实现的覆盖度不一致。有些边界写法在一个解析器里能过、在另一个里报错。

怎么选

场景建议理由
API 请求 / 响应JSON无歧义、解析快、生态一致
K8s / CI 流水线配置YAML已是事实标准,且需要注释
数据交换 / 落盘存储JSON类型明确,不会猜错
需要人频繁手改的配置YAML可读性与注释更重要
有大量重复配置块YAML锚点引用能显著减少重复

一个实用的折中方案:内部存 JSON,给人看的配置用 YAML 并配好校验。很多工具链就是这么做的 —— 构建时把 YAML 转成 JSON 再喂给下游。

两种格式互转可以直接用 JSON ⇄ YAML 转换。转完记得检查一眼数字和布尔值有没有被隐式改变类型,特别是版本号这类字段。

继续阅读