JSON vs YAML:何时使用哪种格式?
· Cosyslabs
JSON是API、数据交换和机器生成配置的正确选择。YAML更适合由人工编写的配置文件,在这些文件中注释、可读性和最少的标点符号非常重要。YAML是JSON的超集——每个有效的JSON文档都是有效的YAML,但YAML有一些重要的陷阱,在采用之前必须了解。
语法比较
// JSON
{
"server": {
"host": "localhost",
"port": 8080,
"tls": true
},
"database": {
"url": "postgres://localhost/mydb",
"pool": {
"min": 2,
"max": 10
}
},
"features": ["auth", "api", "admin"]
}
# YAML — 相同的数据,更易读
server:
host: localhost
port: 8080
tls: true
database:
url: postgres://localhost/mydb
pool:
min: 2
max: 10
features:
- auth
- api
- admin
YAML省去了引号、花括号、方括号和逗号。它使用缩进(仅空格——不使用制表符)来表达结构。
YAML是JSON的超集
您可以直接在YAML文件中嵌入JSON,它是有效的:
# 这是有效的YAML
name: Alice
config: {"debug": true, "level": 3}
这意味着YAML解析器可以解析JSON,YAML到JSON的转换是无损的(除了YAML特有的功能如锚点和注释,JSON无法表示这些)。
JSON的优势
API响应
JSON是REST API的通用语言。每个HTTP客户端,从 curl 到浏览器 fetch,都原生处理JSON:
const response = await fetch("/api/users");
const data = await response.json(); // 内置JSON解析
YAML没有浏览器原生支持,需要额外的解析器依赖(js-yaml约15KB)。
严格的类型处理
JSON有明确的类型:字符串、数字、布尔值、null、数组、对象。YAML从值推断类型,这会导致臭名昭著的错误。
机器生成的数据
生成配置或数据的程序应该输出JSON。JSON是明确的,广泛支持,不依赖于空白字符。
JavaScript生态系统
package.json、tsconfig.json、eslintrc.json——JavaScript工具生态标准化使用JSON。编辑器提供带有自动补全和错误检测的JSON Schema验证。
YAML的优势
人工编写的配置
# YAML允许注释 — JSON不允许
# 这条注释解释了为什么超时时间很高
server:
timeout: 30000 # 毫秒 — 旧版客户端需要更多时间
# 多行字符串在YAML中很易读
message: |
欢迎使用系统。
您的账户已创建。
请检查您的电子邮件进行验证。
Kubernetes、GitHub Actions、Docker Compose
云原生生态系统将YAML标准化用于清单和流水线:
# GitHub Actions工作流
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
多行字符串
YAML使用块标量优雅地处理多行字符串:
# 字面量块标量 — 保留换行符
description: |
第一行。
第二行。
第三行。
# 折叠块标量 — 换行符变为空格
summary: >
这段长文本在
解析时将被折叠
成一行。
JSON需要转义的 \n:
{
"description": "第一行。\n第二行。\n第三行。"
}
YAML的陷阱(挪威问题及其他)
YAML的类型推断导致了真实的生产事故。
挪威问题
countries:
- GB
- DE
- NO # YAML 1.1将此解析为布尔值false!
- SE
在YAML 1.1(许多旧版解析器使用)中,no、NO、No 被解析为 false。同样,yes、YES、Yes 变为 true。YAML 1.2(2009年)移除了这一行为,但许多解析器仍然实现1.1。
修复:对可能被误解的值加引号:
countries:
- "GB"
- "DE"
- "NO" # 现在安全地是字符串
- "SE"
八进制数字解析
file_permissions: 0777 # YAML 1.1:解析为八进制511,而非十进制777!
port: 0755 # 八进制493
在YAML 1.2中,前导零不表示八进制。在1.1中,表示。对精度重要的数值加引号。
缩进错误
YAML只使用空格——混合使用制表符和空格会导致解析器错误:
server:
host: localhost
port: 8080 # 这里有制表符 — YAML解析错误!
重复键
config:
debug: true
debug: false # 哪个生效?未定义行为
不同的解析器对重复键的处理方式不同(后者胜出、前者胜出或报错)。
转换
// YAML转JSON(Node.js)
import yaml from "js-yaml";
import fs from "fs";
const yamlContent = fs.readFileSync("config.yaml", "utf8");
const parsed = yaml.load(yamlContent);
const json = JSON.stringify(parsed, null, 2);
import yaml, json
with open("config.yaml") as f:
data = yaml.safe_load(f) # 使用safe_load,不要用load!
print(json.dumps(data, indent=2))
在Python中始终使用 yaml.safe_load(),而不是 yaml.load()。不安全版本可以通过YAML反序列化执行任意Python代码——这是一个已知的RCE向量。
决策指南
| 场景 | 选择 |
|---|---|
| REST API响应 | JSON |
| gRPC / Protocol Buffers | 两者都不(二进制) |
package.json、tsconfig.json | JSON |
| Kubernetes清单 | YAML |
| GitHub Actions / CI | YAML |
| Docker Compose | YAML |
| Ansible Playbooks | YAML |
| 需要注释的配置 | YAML |
| 机器生成的配置 | JSON |
| 人工编写的配置 | YAML |
| 包含大量字符串的数据 | YAML(无需引号) |
立即试用
使用JSON格式化工具和YAML格式化工具即时在JSON和YAML之间转换——两者都完全在您的浏览器中运行。
更多Cosyslabs工具
- PDF Convert All — 转换、合并和压缩PDF。许多文档生成流水线使用JSON或YAML配置驱动PDF渲染。
- Unit Convert All — 转换配置文件中常见的测量值(如毫秒超时、MB文件大小)。
- Rough Estimator — 估算在大型代码库中将基于JSON的配置系统迁移到YAML(或反之)的工作量。
- Cosyslabs — Dev Tools !、Routine Toolkit等产品背后的工作室。