JSON 工具箱

JSON 解析报错怎么修:Unexpected token 逐条排查

结论:把浏览器、Node、Java、Python 的报错原文翻译成「第几行第几个字符出了什么问题」,再按尾逗号、单引号、注释、控制字符、BOM、截断六个方向逐个排除。

入门约 12 分钟发布于 2026-10-30更新于 2026-11-01
JSON 解析报错排查封面

结论:报 parse 错误时先看报错的行列号定位第一个非法字符,再判断是缺引号、缺逗号、尾逗号还是 BOM 或内容截断,不要从头重读整段。

报错信息从来不告诉你「哪里错了」,它只告诉你「解析器走到哪走不下去了」。这两个位置经常不是同一个地方。

一、先把报错翻译成坐标

同一份坏 JSON,在不同语言里报的错完全不同,但都能换算成「第几行、第几个字符」:

环境 典型报错 怎么读
浏览器 / Node Unexpected token } in JSON at position 42 position 是从 0 开始的字符偏移,不是行号
Node 20+ Unexpected non-whitespace character after JSON at position 42 说明前半段合法,多余内容在 42 之后
Java Jackson Unexpected character ('}' (code 125)): was expecting ... at [Source: (String)..."..." ; line: 3, column: 1] 直接给了行列,最好用
Python json.decoder.JSONDecodeError: Expecting ',' delimiter: line 3 column 1 (char 42) char 是偏移,line/column 才是重点
Go invalid character '}' looking for beginning of object key string 只给字符,需要自己回退定位

拿到 position 之后,把 JSON 粘进 JSON 在线解析,工具会直接把光标停在出错位置并标红行列号——这一步能省掉 90% 的肉眼数数。

二、六类高频错误

1. 尾逗号

{
  "name": "json",
  "version": 1,
}

} 前多了一个逗号。JSON 规范不允许尾逗号,JavaScript 对象字面量允许,所以从代码里复制出来的配置最容易带这个。修复:删掉最后一个逗号;如果这份数据本来就在 JS 文件里,改用 JSON5 转换 而不是硬套 JSON。

2. 单引号与不加引号的键

{ 'name': 'json' }
{ name: "json" }

JSON 的字符串只能用双引号,键也必须是双引号字符串。这两条是 JSON5 / JavaScript 的宽松语法,不是 JSON。字符串内部的双引号要写成 \",反斜杠写成 \\。

3. 注释

{
  // 超时时间,单位毫秒
  "timeout": 3000
}

RFC 8259 的语法里没有注释位置。要么删注释,要么改存 .jsonc / .json5 并用支持注释的解析器。各种「注释方案」的取舍见 JSON 注释怎么写。

4. 字符串里的裸换行与控制字符

{"sql": "SELECT *
FROM t"}

JSON 字符串内不允许直接出现换行、制表符和 U+0000–U+001F 控制字符,必须写成 \n、\t、\u0009。多行文本塞进 JSON 时,先在编辑器里做一次转义,或者用 JSON 压缩与转义 统一处理。

5. BOM 头

Windows 记事本保存的 UTF-8 会带 EF BB BF 三个字节。JSON.parse 遇到 BOM 会直接报 Unexpected token,而肉眼完全看不出来。判断方法:用十六进制查看文件头,或者把内容复制到在线工具里看第一个字符是否显示为 ``。修复:另存为「UTF-8 无 BOM」。

6. 内容被截断

日志只打印了前 4096 个字符、接口被网关截断、下载中断——这类报错的特征是「错误位置在末尾」且括号数量不匹配。先数括号:{、[ 的闭合数量对不上,就是截断而不是语法错。这时候不要修,去拿完整数据。

三、中文与转义相关的两类假故障

中文变成 \u4e2d\u6587:这是合法的 JSON 转义,不是乱码。解析后取值会还原成中文,只有直接看原始字符串时才是 \u 形式。需要给人看的时候用 格式化工具 输出即可;需要在 URL 或日志里保持中文,才需要关心转义策略。

中文变成乱码 涓枃:这是编码问题,不是 JSON 问题。UTF-8 字节被按 GBK 解码就会出现这种「三个字符顶一个汉字」的规律性乱码。检查响应头的 Content-Type: application/json; charset=utf-8,以及读文件时有没有显式指定 encoding='utf-8'。

四、五分钟修复流程

  1. 贴进工具:先用 在线解析 定位第一个错误位置,一次只修一个;
  2. 修完再校验:每修一处重新解析,避免一次改多处导致新错误覆盖旧错误;
  3. 压缩一次:用 压缩 去掉空白再解析,能区分「结构错」和「空白/换行引起的问题」;
  4. 结构对比:如果是改动后突然报错,用 JSON 对比 和上一版比,差异往往就是那一个逗号;
  5. 字段级校验:语法通过但业务报错(缺字段、类型不对),是 JSON Schema 校验 的范畴,不是语法问题。

五、为什么「看起来一样」的两段 JSON 一段能解析

最常见的原因是不可见字符:全角逗号 ,、全角引号 “”、不换行空格 U+00A0、零宽空格 U+200B。它们和半角字符在屏幕上几乎无法区分,但都不是 JSON 语法的一部分。

判断办法只有一个:把出错字符前后的内容复制出来,逐字节看码点。在浏览器控制台里执行下面这段,能直接列出所有非 ASCII 且不属于中文区间的字符:

[...text].filter((ch) => {
  const code = ch.codePointAt(0);
  return code > 127 && !(code >= 0x4e00 && code <= 0x9fff);
});

输出里出现 0x201c(左双引号)、0xff0c(全角逗号)、0x00a0,就是它们的问题。

六、预防比修复便宜

  • 配置类文件在提交前跑一次解析校验,CI 里一行 node -e "JSON.parse(require('fs').readFileSync('config.json','utf8'))" 就够;
  • 接口返回统一用序列化库生成,不要手写拼接字符串——手拼是尾逗号和漏引号的唯一来源;
  • 日志打印 JSON 时先 JSON.stringify,不要直接模板拼接,避免半截内容被当成完整报文。

常见问题

如何快速定位 JSON 语法错误的位置?

先拿解析器给出的 position 或 line/column,position 是从 0 开始的字符偏移,不是行号;Java Jackson 与 Python 报告里会直接给出行列。把 JSON 粘进 JSON 在线解析,工具会把光标停在出错位置并标红行列号,能省掉大部分肉眼数数。若错误出现在开头,先检查文件头是否带 BOM,以及有没有不可见字符。

为什么从代码里复制出来的配置最容易带尾逗号?

JSON 规范不允许尾逗号,而 JavaScript 对象字面量允许,从 JS 代码里复制出来的配置就很容易带进这个逗号。修复只需删掉最后一个逗号;如果这份数据本来就该留在 JS 文件里,改用 JSON5 转换 比硬套 JSON 更合适。

是否可以把带注释的配置文件直接当 JSON 解析?

不行,RFC 8259 的语法里没有注释位置,直接解析会报错。要么删掉注释,要么改存 .jsonc / .json5 并使用支持注释的解析器。各种注释方案的取舍见 JSON 注释怎么写。