JSON 是什么
JSON(JavaScript Object Notation)是当下最通用的数据交换格式:接口返回、配置文件、日志埋点、前后端通信几乎都离不开它。它看起来像 JavaScript 的对象字面量,但两者并不等价,很多“接口报错”“解析失败”的问题,根源都在于把二者混为一谈。
本文从语法规则讲起,覆盖六种数据类型、嵌套、转义,再给出 JavaScript、Python、Java 和 HTTP 请求的实战代码,最后整理常见错误、性能与安全建议,以及常用在线工具。
一、JSON 是什么
JSON 是一种轻量级的纯文本数据格式,由 Douglas Crockford 在 2001 年提出,现由 RFC 8259 与 ECMA-404 标准化。它的三条核心特征:
- 与语言无关:任何语言都能解析,不依赖 JavaScript 运行时。
- 结构简单:只有对象和数组两种复合结构,其余都是标量。
- 可读性强:键值对形式,人眼可直接阅读和手改。
与 JavaScript 对象字面量相比,JSON 的约束更严格:
| 对比项 | JSON | JavaScript 对象字面量 |
|---|---|---|
| 键名 | 必须用双引号包裹 | 双引号、单引号或省略均可 |
| 注释 | 不支持 | 支持 // 与 /* */ |
| 尾逗号 | 不允许 | 允许 |
| 特殊值 | 只允许 null | 还支持 undefined、函数、Symbol |
| 数值 | 不允许 NaN、Infinity | 允许 |
二、六种数据类型
| 类型 | 示例 | 说明 |
|---|---|---|
| 字符串 string | "zjson" | 必须双引号,支持转义字符 |
| 数值 number | 4.9、-12、1e3 | 不区分整数与浮点 |
| 布尔 boolean | true、false | 小写,不能写成 True/False |
| 空值 null | null | 表示“无值”,不是 0 或空串 |
| 对象 object | {"k":"v"} | 无序键值对集合 |
| 数组 array | [1,2,3] | 有序列表,元素类型可混合 |
一个覆盖全部类型的完整示例:
{
"id": 1001,
"name": "zjson",
"verified": true,
"score": 4.9,
"avatar": null,
"tags": ["json", "api", "tutorial"],
"profile": {
"city": "杭州",
"since": "2023-05-01"
}
}注意:顶层结构既可以是对象,也可以是数组(如 [{"id":1},{"id":2}]),实际接口中对象更常见,数组常用于批量数据。
三、语法规则清单
- 数据由键值对(对象)或值列表(数组)组成。
- 键必须是双引号字符串,不能用单引号或裸标识符。
- 键与值之间用英文冒号
:分隔,成员之间用英文逗号,分隔。 - 最后一个成员后面不能有逗号。
- 不支持任何注释,需要说明时只能另加字段(如
"_comment")。 - 数字不能有前导零(
01非法),小数点前后必须有数字。 - 字符串必须使用双引号,内部双引号需转义为
\"。 - 文件编码推荐 UTF-8,HTTP 传输时声明
Content-Type: application/json; charset=utf-8。
四、字符串与转义字符
| 转义 | 含义 | 示例 |
|---|---|---|
\" | 双引号 | "say \"hi\"" |
\\ | 反斜杠 | "C:\\temp\\a.txt" |
\/ | 正斜杠(可选) | "a\/b" |
\n | 换行 | "line1\nline2" |
\t | 制表符 | "a\tb" |
\uXXXX | Unicode 码点 | "\u4f60\u597d" 即“你好” |
中文、日文、Emoji 建议直接写 UTF-8 字符,不要手动转成 \uXXXX;只有传输链路强制 ASCII 时才需要转义,Python 的 ensure_ascii=False 就是为此而生。
五、嵌套结构与取值
真实接口的数据往往多层嵌套,先看一个订单示例:
{
"orderId": "A20261027001",
"amount": 299.00,
"customer": {
"name": "张三",
"vip": true,
"contacts": [
{ "type": "phone", "value": "13800000000" },
{ "type": "email", "value": "zhangsan@example.com" }
]
},
"items": [
{ "sku": "P-100", "qty": 2, "price": 99.50 },
{ "sku": "P-200", "qty": 1, "price": 100.00 }
]
}对应取值方式:
| 目标 | JSONPath | JavaScript | Python |
|---|---|---|---|
| 客户姓名 | $.customer.name | obj.customer.name | obj["customer"]["name"] |
| 第一个商品 SKU | $.items[0].sku | obj.items[0].sku | obj["items"][0]["sku"] |
| 所有商品 SKU | $.items[*].sku | obj.items.map(i => i.sku) | [i["sku"] for i in obj["items"]] |
六、实战代码
6.1 JavaScript:解析、序列化与安全取值
const text = '{"name":"zjson","tags":["json","api"],"profile":{"city":"杭州"}}';
// 解析:字符串 -> 对象
const data = JSON.parse(text);
console.log(data.profile.city); // 杭州
// 序列化:对象 -> 字符串,第三个参数为缩进空格数
const pretty = JSON.stringify(data, null, 2);
console.log(pretty);
// replacer:排除敏感字段
const safe = JSON.stringify(data, (key, value) =>
key === "password" ? undefined : value
);
// reviver:把日期字符串还原成 Date 对象
const withDate = JSON.parse('{"created":"2026-10-27T10:00:00Z"}', (key, value) =>
key === "created" ? new Date(value) : value
);
console.log(withDate.created.getFullYear()); // 2026
// 解析失败必须捕获,否则会抛出 SyntaxError
try {
JSON.parse('{"a":1,}');
} catch (e) {
console.error("JSON 格式错误:", e.message);
}取深层字段时建议逐层判空,避免 Cannot read properties of undefined:
const city = data?.profile?.city ?? "未知";
// 或者用可选链 + 默认值
const firstTag = data.tags?.[0] || "无标签";6.2 Python:读写文件与中文处理
import json
raw = '{"name": "zjson", "tags": ["json", "api"]}'
# 字符串 -> dict
data = json.loads(raw)
print(data["tags"][0]) # json
# dict -> 字符串:ensure_ascii=False 保留中文,indent=2 美化
text = json.dumps(data, ensure_ascii=False, indent=2)
print(text)
# 读写文件
with open("config.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
with open("config.json", "r", encoding="utf-8") as f:
loaded = json.load(f)
# 解析异常
try:
json.loads('{"a": 1,}')
except json.JSONDecodeError as e:
print("第", e.lineno, "行第", e.colno, "列出错:", e.msg)大整数(如订单号、雪花 ID)在 Python 中能精确表示,但传给 JavaScript 会因 Number.MAX_SAFE_INTEGER(2^53-1)丢精度,建议序列化成字符串。
6.3 Java:Jackson 反序列化到对象
import com.fasterxml.jackson.databind.ObjectMapper;
public class User {
public String name;
public int age;
public java.util.List<String> tags;
}
ObjectMapper mapper = new ObjectMapper();
// JSON -> 对象
User user = mapper.readValue("{\"name\":\"zjson\",\"age\":3}", User.class);
// 对象 -> 美化 JSON
String pretty = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(user);
// 反序列化未知字段时忽略,避免上线新增字段导致报错
mapper.configure(
com.fasterxml.jackson.databind.DeserializationFeature
.FAIL_ON_UNKNOWN_PROPERTIES, false
);6.4 发起 JSON 请求
# curl 提交 JSON 必须显式声明 Content-Type
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json; charset=utf-8" \
-d '{"name":"张三","age":28}'// 浏览器 fetch
const res = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "张三", age: 28 }),
});
const result = await res.json();6.5 JSON Schema:给数据加约束
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["name", "age"],
"properties": {
"name": { "type": "string", "minLength": 1 },
"age": { "type": "integer", "minimum": 0 },
"tags": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true
}
},
"additionalProperties": false
}配合 jsonschema(Python)或 ajv(Node.js)可在入库前拦截脏数据,避免“字段缺失”这类线上问题。
七、八个高频错误
| 错误写法 | 原因 | 正确写法 |
|---|---|---|
{name:"a"} | 键没加双引号 | {"name":"a"} |
{'name':'a'} | 用了单引号 | {"name":"a"} |
{"a":1,} | 多余尾逗号 | {"a":1} |
// 注释 | JSON 不支持注释 | 删除,或改用 JSON5/JSONC |
{"a":NaN} | 非法数值 | 改用 null 或字符串 |
{"a":01} | 数字前导零 | {"a":1} |
{"a":undefined} | 非 JSON 值 | {"a":null} |
| BOM 头或全角标点 | 隐藏字符污染 | 用编辑器转为 UTF-8 无 BOM、半角标点 |
排查顺序建议:先格式化看结构,再看报错的行列号,最后检查隐藏字符。在线工具里粘贴即可定位。
八、性能与安全
- 大文件用流式解析:几十 MB 以上不要一次性
JSON.parse,Python 用ijson,Java 用 Jackson Streaming API。 - 数字精度:超过 2^53-1 的整数(订单号、长 ID)序列化为字符串,否则前端会悄悄变成近似值。
- 原型污染:合并 JSON 到对象前过滤
__proto__、constructor、prototype键。 - 不要用 eval:
eval("(" + text + ")")解析 JSON 会执行任意代码,永远用JSON.parse。 - XSS:JSON 里的字符串渲染到页面前必须转义,避免
<script>注入。 - 深度限制:对不可信输入限制嵌套层数和数组长度,防止解析耗尽内存。
九、常用在线工具
调试 JSON 时,这几步最常用:格式化、校验、压缩、格式转换。
- JSON 在线格式化:一键缩进、排序、语法高亮,报错会标出行列位置。
- JSON 校验:检查合法性并定位错误字符。
- JSON 压缩:去掉空白,减小传输体积。
- JSON 对比:比较两份配置的差异。
- JSON 着色高亮:可读性预览,适合截取示例给文档或同事。
- JSON 转 YAML、JSON 转 Excel:配置与报表场景常用。
十、常见问题
1. 接口返回中文变成 \u4f60 怎么办?
这是服务端开启了 ASCII 转义(如 Python 默认 ensure_ascii=True),数据本身没坏。让服务端设置 ensure_ascii=False,或前端解析后用 JSON.parse 即可正常显示。
2. 为什么请求体里 JSON 要用字符串发送?
HTTP 传输的是文本,body 必须是字符串,所以要先 JSON.stringify。同时声明 Content-Type: application/json,否则服务端可能按表单解析。
3. JSON 键的顺序会变吗?
规范上对象是无序的,部分语言/库在解析后不保证原顺序。依赖顺序的业务(如签名)应显式排序后再序列化。
4. 后面能加注释吗?
标准 JSON 不支持。工程里可用 JSON5/JSONC(VSCode 配置文件格式),但对外接口请保持标准 JSON。
5. JSON 和 JSONP 是一回事吗?
不是。JSONP 是早年的跨域方案,通过 <script> 加载并执行回调,现已被 CORS 取代,存在安全风险,不建议使用。
结语
JSON 的规则不多,但每一条都可能让解析失败。掌握六种类型、双引号键名、无注释无尾逗号这三条底线,再配合格式化与校验工具,绝大多数问题都能在几秒内定位。需要处理本文中的示例数据,可直接把内容粘贴到 JSON 格式化工具 里试跑。
所属版权:JSON工具 JSON工具
原文路径:
转载声明:转载时必须以链接形式注明原始出处及本声明。