Uvlio

Command Palette

Search for a command to run...

返回文章列表
技术文章

合法的 JSON 为什么还会报错:逗号、数字与转义

JSON 看起来很宽松,因为它长得像 JavaScript,但它不是。JSON 的语法很小而且刻意严格,大多数解析失败都来自那么几种原因,好的错误信息会直接指出来。真正麻烦的是那些能正常解析、但内容已经错了的情况。
limitcool 维护的 Uvlio 编辑团队2026-05-177 分钟阅读
主题封面开发工具JSONPretty Print

合法的 JSON 为什么还会报错:逗号、数字与转义

JSON 的语法比看起来严格得多。解析器报的位置到底说明什么、长 ID 为什么会变值,以及格式化工具永远发现不了什么。

文章主题预览
{"name":"Ava","roles":["admin"]}
format before review
validate structure first
关联工具
JSON 格式化文本清理
阅读重点
1理解原理
2检查边界
3使用工具

原创流程图

合法的 JSON 为什么还会报错:逗号、数字与转义

这张图由 Uvlio 为本文工作流生成,用来说明从输入检查到输出判断的基本路径。
1

理解原理

检查后再进入下一步

2

检查边界

检查后再进入下一步

3

使用工具

检查后再进入下一步

维护与复核
维护者:limitcool。阅读时可重点关注技术原理、处理边界、隐私风险和可验证事实。
语法比大多数人以为的更小

JavaScript 里合法、JSON 里非法的写法有四类:最后一个元素后面的尾逗号、单引号字符串、不带引号的对象键,以及注释。NaN 和 Infinity 也不是合法数字,前导加号和前导零同样不允许。手写的 JSON 基本都栽在其中之一。如果这个配置文件是人写的而不是程序生成的,先检查每个数组和对象的最后一个元素——尾逗号是最常见的单一原因。

要看错误位置,而不只是错误文字

解析器报的是它放弃的偏移量,通常在真正的错误之后而不是错误本身上。字符串没闭合会报到文件末尾,因为解析器一直往后找收尾的引号。第 40 行的意外符号,往往意味着第 39 行少了一个逗号。先做格式化:结构缩进之后,肉眼找不配对的花括号,比数字符快得多。

数字是数据悄悄丢失的地方

JSON 没有规定数值精度,几乎所有解析器都把数字读成 IEEE-754 双精度。它只能精确表示到 2^53,约九千万亿。19 位的推特式 ID 或 Snowflake ID 超过了这个范围,会被静默四舍五入,末尾几位就变了。此时 JSON 依然合法,值却已经错了。任何装不进 53 位的标识都应该用字符串传输,用大整数存金额的最小单位也是同理。

重复键的行为各家不同

规范没有规定同一个对象里出现两次相同键时该怎么办。多数解析器保留最后一个,有的保留第一个,也有少数直接报错。当请求体是靠字符串拼接或模板合并生成时,这一点尤其危险,因为重复在渲染结果里看不出来。键顺序也一样有歧义:对象按定义就是无序的,所以排序键适合用来比对两份数据,但绝不能用来承载含义。

转义与 Unicode

字符串内部的反斜杠、双引号,以及 U+0020 以下的控制字符必须转义。\uXXXX 表示的是一个 UTF-16 码元,所以基本多文种平面之外的字符——emoji、生僻汉字——需要用两个转义组成的代理对。落单的代理项在技术上是畸形的,后续某个环节一定会变成替换字符。如果中文或日文变成了问号和方块,那么编码是在 JSON 参与之前就坏掉的,这份数据只是症状,不是原因。

压缩和格式化解决的是两件事

格式化是给人读的,压缩是为了传输字节。一旦开启传输压缩,压缩带来的收益比看上去小得多,因为 gzip 和 brotli 处理重复空白很高效。应该在发送这一步压缩,源码仓库里保留格式化版本,绝不要把压缩后的内容当成给人编辑的文件存下来。

格式化工具回答不了的问题

格式化只回答一个问题:这是不是格式良好的 JSON。它不知道必填字段有没有缺、某个字符串本该是数字、空数组表示「没有」还是「没加载」。这些是 schema 层面的问题。一份格式完美的数据照样可能被接口拒绝,所以格式化成功应该看成排查的开始,而不是结束。

常见问题

尾逗号为什么会让 JSON 解析失败?

JSON 语法里根本没有这条规则。JavaScript 容忍它,JSON 不容忍,这也是手写文件解析失败最常见的原因。

长 ID 传一圈回来为什么变了?

它被解析成了双精度浮点数。超过 2^53 的整数无法精确表示,低位会被舍入。这种长度的标识应该用字符串传。

JSON 文件里能写注释吗?

标准 JSON 不行。有些工具支持 JSON5 或 JSONC,但走接口的内容应该默认注释会导致解析错误。常见变通是加一个 "_comment" 键。

发请求前应该先压缩吗?

只有在没开传输压缩时才值得。gzip 已经消化掉了绝大部分美化排版的成本,通常可读性更划算。