首页 / 博客 / 详情

JSON 是什么

作者:sa | 2026-11-04 | 浏览 20 JSON JSON工具 JSON格式化

JSON(JavaScript Object Notation)是当下最通用的数据交换格式:接口返回、配置文件、日志埋点、前后端通信几乎都离不开它。它看起来像 JavaScript 的对象字面量,但两者并不等价,很多“接口报错”“解析失败”的问题,根源都在于把二者混为一谈。

本文从语法规则讲起,覆盖六种数据类型、嵌套、转义,再给出 JavaScript、Python、Java 和 HTTP 请求的实战代码,最后整理常见错误、性能与安全建议,以及常用在线工具。

一、JSON 是什么

JSON 是一种轻量级的纯文本数据格式,由 Douglas Crockford 在 2001 年提出,现由 RFC 8259 与 ECMA-404 标准化。它的三条核心特征:

  • 与语言无关:任何语言都能解析,不依赖 JavaScript 运行时。
  • 结构简单:只有对象和数组两种复合结构,其余都是标量。
  • 可读性强:键值对形式,人眼可直接阅读和手改。

与 JavaScript 对象字面量相比,JSON 的约束更严格:

对比项JSONJavaScript 对象字面量
键名必须用双引号包裹双引号、单引号或省略均可
注释不支持支持 // 与 /* */
尾逗号不允许允许
特殊值只允许 null还支持 undefined、函数、Symbol
数值不允许 NaN、Infinity允许

二、六种数据类型

类型示例说明
字符串 string"zjson"必须双引号,支持转义字符
数值 number4.9、-12、1e3不区分整数与浮点
布尔 booleantrue、false小写,不能写成 True/False
空值 nullnull表示“无值”,不是 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}]),实际接口中对象更常见,数组常用于批量数据。

三、语法规则清单

  1. 数据由键值对(对象)或值列表(数组)组成。
  2. 键必须是双引号字符串,不能用单引号或裸标识符。
  3. 键与值之间用英文冒号 : 分隔,成员之间用英文逗号 , 分隔。
  4. 最后一个成员后面不能有逗号。
  5. 不支持任何注释,需要说明时只能另加字段(如 "_comment")。
  6. 数字不能有前导零(01 非法),小数点前后必须有数字。
  7. 字符串必须使用双引号,内部双引号需转义为 \"。
  8. 文件编码推荐 UTF-8,HTTP 传输时声明 Content-Type: application/json; charset=utf-8。

四、字符串与转义字符

转义含义示例
\"双引号"say \"hi\""
\\反斜杠"C:\\temp\\a.txt"
\/正斜杠(可选)"a\/b"
\n换行"line1\nline2"
\t制表符"a\tb"
\uXXXXUnicode 码点"\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 }
  ]
}

对应取值方式:

目标JSONPathJavaScriptPython
客户姓名$.customer.nameobj.customer.nameobj["customer"]["name"]
第一个商品 SKU$.items[0].skuobj.items[0].skuobj["items"][0]["sku"]
所有商品 SKU$.items[*].skuobj.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 时,这几步最常用:格式化、校验、压缩、格式转换。

十、常见问题

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 格式化工具 里试跑。

上一篇
Clawdbot 本地私有 AI 助手部署实操手册:搭建 7×24 小时可执行任务的智能管家
下一篇
没有了