JSON 语法
JSON 的语法规则其实只有一页纸,但线上接口的解析报错,绝大多数都出自这页纸上的细节:键名忘了加双引号、末尾多了一个逗号、数字带了前导零、文件开头混进了 BOM。本文把 JSON 的语法拆成结构、类型、字符三个层面逐条讲清,再给出可直接对照的错误清单,帮助你从“能看懂”走到“能写对、能排错”。
一、JSON 的语法结构
RFC 8259 对 JSON 的定义非常克制:一段 JSON 文本就是一个“值”(value)。值只有两种复合形态——对象和数组,其余都是标量。可以把它抽象成下面这棵树:
value
├── object { "key": value, ... }
├── array [ value, ... ]
├── string "text"
├── number 123 / -4.5 / 1e3
├── boolean true / false
└── null null由此可以推出三条最基本的语法约束:
- 顶层只能有一个值:要么是一个对象,要么是一个数组,不能是两段并列的内容,也不能是裸的键值对。
- 复合结构必须闭合:
{与}、[与]必须成对,且不能交叉嵌套。 - 分隔符只用英文符号:冒号
:分隔键和值,逗号,分隔成员,全部是半角字符。
二、对象:键必须是被双引号包裹的字符串
对象是无序的键值对集合,写法为 { "key": value }。这里有一个新手最容易忽略的点:键名必须是双引号字符串,不能是单引号,也不能是裸标识符。
// 合法
{ "name": "zjson", "version": 2 }
// 非法:键没有引号
{ name: "zjson" }
// 非法:键用了单引号
{ 'name': 'zjson' }另外几条容易踩的规则:
- 键与值之间必须有冒号,冒号两侧的空白可有可无。
- 成员之间用逗号分隔,最后一个成员后面不能有逗号。
- 同一个对象内不建议出现重复键。规范没有强制禁止,但不同解析器的处理方式不一致(有的保留最后一个,有的保留第一个),会给排查带来麻烦。
- 对象不能直接作为另一个对象的键,键只能是字符串。
三、数组:有序的值列表
数组用方括号包裹,元素之间用逗号分隔,元素可以是任意 JSON 值,类型允许混合:
[1, "two", true, null, { "id": 3 }, [4, 5]]数组同样不允许尾逗号,也不允许空槽位(如 [1,,3])。空数组写作 [],空对象写作 {},两者都是合法的。
实际接口中常见两种顶层结构:单个资源用对象,批量数据用数组。[{"id":1},{"id":2}] 是合法的顶层 JSON,解析后就是一个长度为 2 的列表。
四、六种数据类型与严格写法
| 类型 | 合法示例 | 关键规则 |
|---|---|---|
| 字符串 | "zjson" | 必须双引号,内部双引号与反斜杠需转义 |
| 数值 | 0、-12、4.5、1e3 | 不区分整数与浮点,禁止前导零、NaN、Infinity |
| 布尔 | true、false | 只能小写,不能写成 True/False |
| 空值 | null | 只能小写,表示“无值”,不等于 0 或空串 |
| 对象 | {"a":1} | 键必须是双引号字符串,成员间用逗号 |
| 数组 | [1,2,3] | 有序,元素类型可混合,禁止尾逗号 |
4.1 数字的写法
JSON 数字的语法比 JavaScript 严格,下面这些写法都会导致解析失败:
01 // 非法:前导零
+1 // 非法:不允许正号
.5 // 非法:小数点前必须有数字
5. // 非法:小数点后必须有数字
0x1F // 非法:不支持十六进制
NaN // 非法:非数字
Infinity // 非法:无穷大正确的写法是 1、-1、0.5、5.0、1e3、1E-3。需要注意精度问题:超过 2^53-1 的整数(如订单号、雪花 ID)在 JavaScript 中会丢失精度,建议在接口里直接以字符串形式返回。
4.2 字符串与转义字符
字符串必须使用双引号。内部需要出现的双引号、反斜杠、换行等字符,必须使用转义序列:
| 转义 | 含义 | 示例 |
|---|---|---|
\" | 双引号 | "say \"hi\"" |
\\ | 反斜杠 | "C:\\temp\\a.txt" |
\/ | 正斜杠(可选) | "a\/b" |
\b | 退格 | "a\bb" |
\f | 换页 | "a\fb" |
\n | 换行 | "line1\nline2" |
\r | 回车 | "a\rb" |
\t | 制表符 | "a\tb" |
\uXXXX | Unicode 码点 | "\u4f60\u597d" 即“你好” |
标准 JSON 不允许使用单引号字符串,也不支持多行字符串。中文、日文、Emoji 建议直接写 UTF-8 字符,只有在链路强制 ASCII 时才需要转成 \uXXXX。
五、空白、编码与注释
空白字符(空格、制表符、换行、回车)可以出现在任意两个语法记号之间,用于美化排版,但不影响数据本身。因此下面两种写法在解析后完全等价:
{"a":1,"b":2}
{
"a": 1,
"b": 2
}空白只能出现在记号之间。如果把它塞进键名或数字内部,例如 {"na me": 1} 是合法的(空格属于键名的一部分),而 {"a": 1 2} 则会直接报错。
编码方面:
- JSON 文本推荐使用 UTF-8,传输时声明
Content-Type: application/json; charset=utf-8。 - 文件保存为 UTF-8 无 BOM。BOM 头对 JSON 解析器是非法字符,常表现为“第一行第一列报错”,肉眼却看不到异常。
- 文言文件里的全角引号、全角逗号、全角冒号都属于非法字符,粘贴时尤其容易混入。
- 标准 JSON 不支持任何注释。需要说明信息时,只能新增字段(如
"_comment"),或改用 JSON5 / JSONC 等扩展格式。
六、一个覆盖全部语法的完整示例
{
"id": 1001,
"name": "zjson",
"verified": true,
"score": 4.9,
"balance": null,
"tags": ["json", "syntax", "api"],
"contact": {
"city": "杭州",
"phone": "13800000000"
},
"orders": [
{ "sku": "P-100", "qty": 2, "price": 99.5 },
{ "sku": "P-200", "qty": 1, "price": 100.0 }
]
}这段文本包含了对象、数组、字符串、数值、布尔和 null 六种类型,也包含了两层嵌套。校验时可以重点检查:所有键是否有双引号、每层是否闭合、最后一个成员后面是否多了逗号。
七、高频语法错误对照表
| 错误写法 | 错误原因 | 正确写法 |
|---|---|---|
{name:"a"} | 键名缺少双引号 | {"name":"a"} |
{'name':'a'} | 使用了单引号 | {"name":"a"} |
{"a":1,} | 多余的尾逗号 | {"a":1} |
[1,2,] | 数组尾逗号 | [1,2] |
{"a":01} | 数字前导零 | {"a":1} |
{"a":NaN} | 非法数值 | {"a":null} 或字符串 |
{"a":undefined} | 非 JSON 值 | {"a":null} |
{"a":1} {"b":2} | 顶层出现多个值 | 合并为一个对象或改为数组 |
// 注释 | 标准 JSON 不支持注释 | 删除注释或改用 JSONC |
| 文件带 BOM / 全角标点 | 隐藏字符与非法字符 | 转 UTF-8 无 BOM,替换为半角符号 |
八、怎么快速定位语法错误
遇到解析失败时,可以按下面的顺序排查:
- 先格式化:把整段文本交给格式化工具,结构错乱、括号不匹配会立刻暴露。
- 看报错行列号:多数解析器会给出出错位置。注意报错位置有时指向问题字符的下一个记号,需要往前看一两个字符。
- 检查隐藏字符:重点看文件开头是否有 BOM、是否混入全角标点、是否有从网页复制来的不可见字符。
- 缩小范围:删掉一半内容再校验,用二分法快速锁定出错片段。
手工排查效率低时,直接使用在线工具会更快:JSON 在线格式化 可以在美化同时标出语法错误位置,JSON 校验工具 用于确认文本是否合法,JSON 压缩 则适合在确认无误后减小体积。若需要比对两份配置的差异,可用 JSON 对比工具。
九、JSON 与 JSON5:什么时候可以“放宽语法”
因为标准 JSON 太严格,工程里出现了 JSON5、JSONC 等扩展格式,它们允许单引号、注释、尾逗号、裸键名等写法。典型场景是编辑器配置文件(如 VS Code 的 settings.json 允许注释)。但需要注意:
- 对外提供的接口、跨语言传输的数据,必须使用标准 JSON。
- 扩展格式只能保证被特定工具解析,换一个解析器就可能失败。
- 如果配置里必须写注释,优先确认目标解析器是否支持 JSONC,而不是默认所有环境都支持。
十、小结
JSON 语法可以用三句话记住:顶层一个值、键名双引号、末尾无逗号。再叠加数字与字符串的严格写法、UTF-8 无 BOM 编码,就能覆盖日常开发中绝大多数语法问题。写完 JSON 后先过一遍格式化或校验工具,比在代码里调试解析异常省事得多。
所属版权:JSON工具 JSON工具
原文路径:
转载声明:转载时必须以链接形式注明原始出处及本声明。