← 全部文章

如何格式化、校验、压缩和查看 JSON

用 JavaScript、Python、jq、Prettier、VS Code 或浏览器本地工具格式化并校验 JSON;然后在压缩文本、美化输出和树形视图之间做选择,同时不悄悄改动数据。

先给结论: 如果文本已经是合法 JSON,那就解析它、再带缩进重新输出。JavaScript 里用 JSON.stringify(JSON.parse(raw), null, 2),Python 里用 json.dumps(json.loads(raw), indent=2),命令行用 jq . input.jsonpython3 -m json.tool input.json。如果输入里有尾随逗号、单引号、注释或没加引号的键,先用 JSON Fix 修复或校验。

格式化 JSON 不会改变值。它要解决的是:让同一个对象变得足够好读,好让人能复核它、diff 它、贴进 bug 报告,或者提交进仓库 —— 而不用眯着眼睛盯一条长长的单行。

格式化 JSON 到底做了什么

JSON 格式化器解析一个 JSON 值,然后用可预期的空白把它重新序列化:

  • 每个对象成员单独占一行。
  • 嵌套的对象和数组带缩进。
  • 字符串保留双引号。
  • 逗号只出现在值之间,绝不跟在最后一个值后面。
  • 不会引入注释、单引号或 JavaScript 专有的值。

格式化前:

{"user":{"id":"u_123","name":"Ada","roles":["admin","editor"],"active":true}}

用 2 个空格格式化后:

{
  "user": {
    "id": "u_123",
    "name": "Ada",
    "roles": [
      "admin",
      "editor"
    ],
    "active": true
  }
}

这两份文档在 JSON 里描述的是同一个值。JSON token 之间的空白是无意义的,所以缩进和换行对解析器来说不该有任何影响。

"不该"这两个字用得很讲究。好的格式化器会保住 JSON 的值;但只要你喂给它重复的键、超大的数字,或者非 JSON 的 JavaScript 值,解析加序列化这套组合仍然会制造边界情况。下面几节会专门讲这些。

挑对格式化方式

场景 用什么 为什么
浏览器里快速清理 JSON Fix 先修常见的损坏 JSON,再在本地格式化
代码里的 JavaScript 值 JSON.stringify(value, null, 2) 每个 JS 运行时都内置
JavaScript 里的 JSON 文本字符串 JSON.stringify(JSON.parse(raw), null, 2) 格式化之前先校验
Python 脚本或 notebook json.dumps(data, indent=2) Python 内置
Shell 管道或 API 响应 jq . 快、可脚本化、报错清楚
仓库里的机器可读文件 Prettier 在 CI 里保持风格一致
tsconfig.json 或 VS Code 配置 VS Code / Prettier JSONC 能处理 JSONC 的注释和尾随逗号

调试 API 响应时,请用那种遇到坏 JSON 会大声报错的格式化器。

在 JavaScript 里格式化 JSON

对一个 JavaScript 值来说,格式化器就是 JSON.stringify,第三个参数控制缩进:

const value = {
  user: {
    id: 'u_123',
    name: 'Ada',
    roles: ['admin', 'editor'],
    active: true
  }
};

const pretty = JSON.stringify(value, null, 2);
console.log(pretty);

输出:

{
  "user": {
    "id": "u_123",
    "name": "Ada",
    "roles": [
      "admin",
      "editor"
    ],
    "active": true
  }
}

要四个空格就传 4,要制表符就传 '\t'

JSON.stringify(value, null, 4);
JSON.stringify(value, null, '\t');

有个细节容易被忽略:space 参数是有上限的。传 100 并不会得到 100 个空格的缩进 —— JavaScript 把数字缩进封顶在 10 个空格。

格式化一个 JSON 字符串

如果你手上是文本,先解析:

const raw = '{"name":"Ada","active":true}';
const formatted = JSON.stringify(JSON.parse(raw), null, 2);

console.log(formatted);

这比用字符串替换硬塞换行要好得多。JSON 是嵌套语法:字符串里的逗号和数组元素之间的逗号根本不是一回事,靠正则做格式化,早晚会在真实输入上翻车。

用 Node.js 格式化 JSON 文件

写脚本时,把文件读成文本、解析、再写回去,末尾补一个换行,好让 git diff 保持干净:

import { readFile, writeFile } from 'node:fs/promises';

const input = await readFile('input.json', 'utf8');
const value = JSON.parse(input);
const output = `${JSON.stringify(value, null, 2)}\n`;

await writeFile('output.json', output);

如果脚本会覆盖文件、而输入又很重要,那就先写到临时文件 —— 这样解析一旦失败,你还能中止操作。

在 JavaScript 里递归排序键

排序键对稳定的 diff、快照和生成的测试数据很有用。但它不该给数组排序,因为在 JSON 里数组顺序是有意义的。

function sortJsonKeys(value) {
  if (Array.isArray(value)) {
    return value.map(sortJsonKeys);
  }

  if (value && typeof value === 'object' && value.constructor === Object) {
    return Object.keys(value)
      .sort((a, b) => a.localeCompare(b))
      .reduce((result, key) => {
        result[key] = sortJsonKeys(value[key]);
        return result;
      }, {});
  }

  return value;
}

const formatted = JSON.stringify(sortJsonKeys(value), null, 2);

能不排就别排。对人工维护的配置文件来说,保留作者的分组方式,往往比按字母排序更好读。

在 Python 里格式化 JSON

Python 内置的 json 模块流程一样:先 load,再带缩进 dump。

import json

raw = '{"name":"Ada","active":true}'
data = json.loads(raw)

print(json.dumps(data, indent=2))

格式化文件:

import json

with open("input.json", encoding="utf-8") as f:
    data = json.load(f)

with open("output.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2)
    f.write("\n")

排序键:

json.dumps(data, indent=2, sort_keys=True)

如果 JSON 里含有超大的整数 ID,用 Python 格式化通常更稳妥,因为 Python 的整数是任意精度的。JavaScript 把 JSON 数字解析成 Number,无法精确表示每一个 64 位整数。要是你的 JSON 里有 9223372036854775807 这样的 ID,请把它们保留成字符串,或者换一个专门保留大数的解析器。

在命令行里格式化 JSON

jq

用恒等过滤器时,jq 默认就会美化输出:

jq . input.json

存到另一个文件:

jq . input.json > output.json

格式化 curl 的响应:

curl -s https://api.example.com/users | jq .

排序键:

jq --sort-keys . input.json

改成压缩而不是格式化:

jq -c . input.json

要避开这个经典错误:

jq . input.json > input.json

shell 会在 jq 读之前就以写模式打开 input.json,结果就是把文件清空。用临时文件:

tmp="$(mktemp)"
jq . input.json > "$tmp" && mv "$tmp" input.json

不装 jq,用 Python

只要装了 Python,基础的格式化用 json.tool 就够:

python3 -m json.tool input.json

从标准输入读:

printf '%s\n' '{"name":"Ada","active":true}' | python3 -m json.tool

排序键:

python3 -m json.tool --sort-keys input.json

用四个空格:

python3 -m json.tool --indent 4 input.json

在 VS Code 和 Prettier 里格式化 JSON

VS Code 不装扩展就能格式化 .json 文件:打开文件,在命令面板里执行 Format Document,或者用编辑器快捷键。处理单个文件够用了。

面向整个仓库,请用 Prettier,这样格式化才可复现:

npm i -D prettier
npx prettier --write "**/*.{json,jsonc}"
npx prettier --check "**/*.{json,jsonc}"

一份小配置通常就够:

{
  "tabWidth": 2,
  "trailingComma": "none"
}

jsonjsonc 要分清楚:

  • .json 应该是严格 JSON:没有注释,没有尾随逗号。
  • .jsonc 在支持 JSONC 的工具里允许注释和尾随逗号。
  • tsconfig.json 和 VS Code 的 settings.json 虽然扩展名是 .json,编辑器通常按 JSONC 对待。
  • API、包元数据、锁文件和数据源基本都要求严格 JSON。

别以为编辑器格式化过就万事大吉了 —— 只要这个文件会被服务端、API、数据库或构建工具读取,就得确认它是严格 JSON。

什么时候格式化会改变你看到的内容

对合法 JSON 来说,格式化本应保住值。风险来自"解析再序列化"这套行为:

情况 可能发生什么 更稳妥的做法
重复的对象键 很多解析器只保留最后一个值 在数据约定里就把重复键视为非法
超大数字 JavaScript 可能把超过 Number.MAX_SAFE_INTEGER 的整数四舍五入 给大 ID 加引号,或换用支持大数的解析器
JS 里的 NaNInfinity 在数组和对象值里会被序列化成 null 输出 JSON 之前明确地转换它们
undefined、函数、Symbol 这些对象属性会被直接省略 换成明确的 JSON 值
Date 对象 会变成 ISO 字符串 先确认 API 要的是字符串还是时间戳
BigInt JSON.stringify 会抛异常 格式化前先转成字符串

调试时这个区别很重要:格式化一份 JSON 文本文件是一回事,序列化一个活的 JavaScript 对象是另一回事。

为什么你的 JSON 格式化不了

格式化器只能格式化合法 JSON。解析失败,它就没有可缩进的结构。

常见原因:

  • }] 前面有尾随逗号
  • 用单引号包的字符串
  • 没加引号的对象键
  • ///* */ 注释
  • 从 Python 来的 TrueFalseNone
  • 从 JavaScript 来的 undefinedNaNInfinity
  • 复制响应时,JSON 前后带上了多余的日志文本
  • API 响应被截断,缺了闭合的大括号或方括号

要做严格语法检查,用 JSON 校验器。日志、配置片段或大模型输出里的"近似 JSON",先用 JSON Fix 修,再格式化。下一节会讲为什么光靠解析成功还不够。

格式化之前先校验语法

格式化、压缩和查看,起点都是解析输入。而解析成功只说明这段文本在语法上是合法 JSON,它不检查 API 载荷里必填字段在不在、类型对不对。

把它拆成三个独立的问题:

层次 问题 常用工具
语法 这是合法的 JSON 文本吗? JSON.parsepython -m json.tooljq empty
结构 必需的属性和类型都在吗? JSON Schema、Ajv、Pydantic、Zod
业务规则 这个值在当前操作里被允许吗? 应用代码和领域检查

JavaScript 的语法检查:

function validateJsonSyntax(text) {
  try {
    return { valid: true, value: JSON.parse(text) };
  } catch (error) {
    return { valid: false, error: error.message };
  }
}

命令行检查(输入非法时返回非零退出码):

jq empty input.json
python3 -m json.tool input.json > /dev/null

对 API 响应来说,解析之前还要检查 HTTP 状态码和 content-type。一个排版精美的登录页,它仍然是 HTML,不是 JSON。关于用 JSON Schema 做结构校验,见什么是 JSON?

在线格式化 JSON,但不上传你的载荷

本站的 JSON Fix 工具把核心的修复、校验、格式化、压缩、排序和复制流程都放在你的浏览器里运行。格式化器用的模型和本地脚本没什么两样:解析值,可选地对对象键排序,然后以 2 或 4 个空格缩进输出 JSON。

这样用它:

  1. 把最小的、脱敏过的样本粘进输入编辑器。
  2. 选 2 个还是 4 个空格。
  3. 只有当稳定的对象顺序确实有帮助时,才打开 Sort keys。
  4. 损坏的 JSON 点 Repair & Format,严格 JSON 点 Validate。
  5. 把修复后的值用进 API 请求或配置文件之前,先复核一遍。

本地格式化降低了暴露面,但粘贴进来的 bearer token、API key、客户记录或私密配置仍然是敏感信息。放进任何网页、截图、聊天、issue 或 PR 之前,请先脱敏。更完整的隐私流程见在线修复 JSON

先把数据转成 JSON,再格式化

有些人搜"format to JSON",其实想问的是"怎么把另一种数据形态转成 JSON"。那是另一个步骤。

YAML 转格式化的 JSON:

import json
import yaml

with open("config.yaml", encoding="utf-8") as f:
    data = yaml.safe_load(f)

print(json.dumps(data, indent=2))

CSV 转格式化的 JSON:

import csv
import json

with open("users.csv", newline="", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))

print(json.dumps(rows, indent=2))

转换时留意类型。CSV 没有原生的布尔、null、数字、对象或数组类型。邮政编码、商品编码、账号 ID 和大数字 ID 通常必须保持字符串,哪怕它们长得像数字。

更完整的转换流程,见 YAML 转 JSON把 CSV、XML、YAML 转成 JSON

为传输压缩 JSON

压缩是解析一个 JSON 值,再输出成不含无意义空白的形式。它是美化的反向操作 —— 既不是压缩算法,也不是加密。

const minified = JSON.stringify(JSON.parse(raw));
minified = json.dumps(json.loads(raw), separators=(",", ":"))
jq -c . input.json

内嵌的测试数据、需要复制的请求体,或者要求每行一条记录的系统,用压缩后的 JSON。可读的源文件请保持格式化状态 —— 除非这个仓库有意存放生成的压缩产物。

一般来说,HTTP 的 gzip 或 Brotli 省下来的比单纯删空白多得多,因为它会压缩重复的属性名和值。网络性能靠传输压缩,压缩 JSON 则用在"只想要紧凑源文本"或"需要按行分帧"的时候。前面关于重复键和大数字的提醒,对走普通 JavaScript 解析器的压缩同样适用。

嵌套很深的载荷用树形视图

如果你要的是可复制的文本、精确的标点或一份 git diff,格式化器最合适。而当你需要在庞大的嵌套载荷里逐层下钻、又不想滚过几千行时,树形查看器就好用了。

任务 最合适的视图
编辑或复制 JSON 文本 格式化器 / 编辑器
确认语法 校验器
展开大响应里的某一个分支 树形查看器
比较两份载荷 语义化 JSON diff
抢救近似 JSON 修复工具,之后再校验

在树里,先看容器类型再看值:{} 是对象,[] 是数组,数组下标是路径的一部分。显示在 users[2].profile.email 的字段,和 users.profile.email 完全不是一回事。空数组、空对象、null、缺失的属性、数字 0 和空字符串,在视觉上应该始终能区分开。

大文件要节制着看:把无关分支折叠起来,搜一个已知的键,先看一条有代表性的记录,别一上来就全展开。树形视图不会把非法 JSON 变合法 —— 先把文本修好,再去看解析结果。

JSON 查看器JSON 校验器JSON Diff 都在浏览器里运行,各自负责同一套流程里的不同步骤。

一套实用的格式化流程

一次性调试:

  1. 把原始 JSON 格式化出来,先看清结构。
  2. 检查你真正关心的那个字段。
  3. 只有当目标端需要单行 JSON 时,才再压缩回去。

代码评审:

  1. 校验严格 JSON。
  2. 应用仓库自己的格式化器。
  3. 除非项目本来就用排序输出,否则别开 sort keys。
  4. 只提交格式化后的数据文件,别捎上无关的生成文件。

生产配置:

  1. 校验语法。
  2. 校验 schema 或必填字段。
  3. 检查大 ID 和可空字段。
  4. 原地重写文件之前先留个备份。

格式化让 JSON 更好读,但它证明不了这份载荷对你的应用是正确的。

格式化问题排查

症状 可能原因 怎么修
格式化器报 "Unexpected token" 输入不是严格 JSON 先看行列号,再修语法
输出的键顺序变了 开了 sort keys,或序列化器重排了对象键 人工分组重要的话就关掉排序
大 ID 变了 JavaScript 数字精度丢失 把 ID 存成字符串,或换用能保留精度的解析器
注释不见了 你是按 JSON 而不是 JSONC 格式化的 注释只保留在 JSONC 文件里
执行完命令文件空了 输出重定向到了同一个输入文件 先写临时文件,再 mv
API 拒绝了格式化后的 JSON 语法过了,但 schema 或业务规则没过 校验必填字段、类型、枚举和 null

常见问题

在 JavaScript 里怎么格式化 JSON?

对 JavaScript 值用 JSON.stringify(value, null, 2)。如果手上是 JSON 字符串,先解析:JSON.stringify(JSON.parse(raw), null, 2)。先解析能在格式化之前确认这段文本确实是合法 JSON。

什么都不安装,怎么格式化 JSON 文件?

用 Python 自带的格式化器:python3 -m json.tool input.json。它会读文件、校验 JSON 并打印格式化结果。想让对象键按字母排序,加上 --sort-keys

格式化 JSON 会改动数据吗?

缩进和换行不会改动 JSON 数据。但"解析再序列化"的工具会暴露一些边界情况:重复的键可能被合并成一个值,JavaScript 可能对超大数字做四舍五入,而 undefined 这类非 JSON 的 JavaScript 值根本无法表示。

为什么我的 JSON 格式化不了?

输入多半不是严格 JSON。常见原因有尾随逗号、单引号、没加引号的键、注释、Python 的 True 这类字面量、JavaScript 的 undefined,或者响应被截断了。先把语法修好或校验一遍。

JSON 用 2 个还是 4 个空格?

JavaScript 和 Web 项目里 2 个空格更常见,某些 Python 和 Java 团队习惯 4 个。缩进宽度属于无意义空白,所以保持一致比选几个空格重要得多。

该不该给 JSON 的键排序?

想要稳定的 diff、生成的测试数据或确定性的快照,就排序。如果现有顺序对人有意义(比如手工维护的配置里那些设置分组),就别排。JSON 数组的顺序是有意义的,所以格式化器不应该给数组排序。

能格式化带注释的 JSON 吗?

严格 JSON 不允许注释。部分编辑器和配置文件用的是 JSONC,它允许注释和尾随逗号,但期待 RFC 风格 JSON 的 API 和解析器会拒绝。JSONC 就按 JSONC 格式化;数据发给 API 之前,先按严格 JSON 校验。

在线格式化 JSON 安全吗?

取决于格式化在哪里运行。JSON Fix 工具把大部分修复和格式化工作放在你的浏览器里做,但把敏感值粘进任何网页、截图、issue 或聊天之前,先脱敏仍然是好习惯。

美化打印和格式化 JSON 是两回事吗?

在常规的 JSON 工具链里,这是同一个操作:解析一个值,带着缩进和换行重新序列化。有些工具把整个编辑器流程叫作"format",但并不存在另一套"JSON 美化打印语法"。

压缩 JSON 算压缩吗?

Minify 去掉的是可选空白。gzip、Brotli 这类压缩会对重复文本做编码,通常能把传输体积再降一大截。两者可以叠加,但真正关键的网络优化是 HTTP 压缩。

什么时候该用 JSON 树形查看器而不是格式化器?

浏览庞大的嵌套载荷用树;需要看到精确文本、编辑、复制或做按行 diff 时用格式化器。两者都需要先有合法 JSON,才能可靠地展示结构。

相关 JSON 工具与指南

参考资料

最后校订于 2026 年 8 月。