← 返回博客首页

JSON.parse 为什么报错:最常见报错与定位思路

最经典的一句报错

SyntaxError: Unexpected token } in JSON at position 5

所有人第一次写 JSON.parse 都被它迎面撞上。报错信息其实信息量很大:它告诉你 第几个字符(position)出问题坏掉的 token 是什么、以及「这是 JSON 语法层面的错,不是取值层面的错」。本文把四类最常见报错逐一拆开,并给一套能落到手头的排错流程。

报错信息怎么读

JSON.parse(arg) 抛出的统一都是 SyntaxError,但它有两个关键字段:

  • position:错误发生的字符下标(0 起);用它可以直接跳到字符串里那个位置看。
  • 消息里的 token:如 }, ``, o, 1——就是那一位实际读到的字符。

大多数解析器/校验工具会把这两者高亮成一个「箭头」指向出错点,这正是定位的起点。

常见错误一:Unexpected token 'x'(意外字符)

JSON.parse('{"a":1,,}')   // Unexpected token ','
JSON.parse("{a:1}")       // Unexpected token 'a'   —— 键缺引号
JSON.parse("{'a':1}")     // Unexpected token ' — 用了单引号

标准化 JSON 的三条「铁律」经常被 JS 户籍惯坏

  1. 键必须双引号,不能裸名也不能单引号;
  2. 注释不允许///* */ 都不能);
  3. ** trailing comma 不允许**——见下。

很多服务端返回的是「类 JSON 但 JavaScript 风格」的字符串,这就要在源头改,而不是在 parse 处硬撑。

常见错误二:Unexpected end of JSON input(未闭合/截断)

JSON.parse('{"a":1')          // Unexpected end of JSON input
JSON.parse('')                // 空串也是同样的错

这通常意味着字符串根本不完整:要么你切了尾巴,要么网络/存储环节把它截断了。凡是报「Unexpected end」且位置在末尾,优先怀疑负载截断,而不是你少写了一个括号。

常见错误三:尾随逗号

{"a":1,}   →  Unexpected token '}'
[1,2,]     →  Unexpected token ']'

JS 的对象/数组字面量允许尾随逗号,于是很自然手滑写进 JSON。排查技巧:很多「JSON 格式化」在线工具会自动在对象末尾补一个逗号,改完直接拿去校验就误报;一定要选「去尾随逗号」或不补逗号的选项。

常见错误四:Unexpected token o(重复 parse / 非字符串)

const obj = {name:'k'};
JSON.parse(obj)       // Unexpected token o in JSON at position 0  ← [object Object] 的 'o'
JSON.parse('123')     // 合法!会是数字,不抛错

传入的必须是一个字符串(或自动转成字符串的合法输入)。传已经解析好的对象,toString 变成 [object Object],于是报 o。

三板斧排错流程

拿到乱成一团的 JSON,别用肉眼盯,按这套来:

  1. 格式化:丢进 JSON 格式化工具,压缩的 JSON 展成树状/带缩进,报错箭头指哪、上下文是什么,一眼可见;这是最常被跳过却最高效的一步。
  2. 字符审计:用「查找替换」把 ,\n{\n[\n 等高危模式显式标出来,重点检查尾随逗号、缺引号键、注释残留;也顺手把响应里混入的 HTML/日志前缀揪出来。
  3. 分段定位:对几百 KB 以上、且报错靠末端的 payload,先取前/后各一段分别 parse,二分缩小问题区间;结合字节偏移确认是不是多字节字符被截断。

为什么「看起来是对的」却 parse 失败

高发的三类错觉:

  • 编辑器/浏览器已帮你转了:复制粘贴时自动把中文引号、全角冒号转成了半角,你以为没问题。
  • 多了一层序列化:后端 JSON.stringify 后再包一层、或前端把字符串再 stringify,解出来是带引号的字符串而不是对象。
  • 经过了编码转义\uXXXX 转义没被正确还原、换行被写成字面换行(JSON 字符串内换行必须 \n 转义)。

自查

把这段会踩坑的例子丢进 JSON 校验/格式化,快速找出三个问题并修正:

{
  name: "k",
  "tags": ["a", "b",],
  "note": "line break
  here"
}

能指出「键缺引号、尾随逗号、字符串内字面换行」三处,并解释每个的报错 token 长什么样,JSON.parse 的报错对你就不再是谜。

常见问题

JSON.parse 报 'Unexpected token o' 是什么意思?

通常是你把一个已经是对象的东西又 parse 了一次:`JSON.parse(object)` 里 object.toString() 得到 `[object Object]`,而 `o` 正是 `[object Object]` 的第一个字母 o。也就是说你传进去的不是字符串(若是字符串传错了会报 Unexpected token 'x',x 是字符本身)。修复:先确认入参确实是字符串,且是一次 parse;存储/传输环节往往容易重复序列化。

为什么把 JSON 复制到编辑器里直接 parse 会报『尾随逗号』?

标准 JSON 语言里**不允许尾随逗号**:`{"a":1,}` 或 `[1,2,]` 都会抛 Unexpected token '}' or ']'。JS 的对象/数组字面量允许尾随逗号,所以手写惯了 JavaScript 就很自然写出了非法 JSON。很多『JSON 格式化』在线工具默认也会在末尾补逗号,导致反馈『我 JSON 明明没问题却报错』。修复:用格式化工具有『去尾随逗号』选项,或手删最后一个逗号再校验。

从服务器拉取的 JSON 总在后半段 parse 失败,怎么办?

优先怀疑**截断**:响应被代理/网关截断、gzip 解压失败、或接口返回了超时产物。判断法:把响应体完整保存,先用 'JSON 校验' 看报错位置——若总是报在末尾某处而非你自己字段附近,或报 'Unexpected end of JSON input',基本就是截断/未闭合。修复:看服务端日志与 Content-Length/Content-Encoding 头,确认返回是否完整;开发时可在 fetch 里打印 response.text() 长度与它声明的长度比对。

JSON 里的字符串明明带有中文/emoji,为什么会 'Unexpected end'?

多数不是内容本身的问题,而是**编码/字节层面的坑**:①用错误的 charset 读(如声明 utf-8 实为 latin-1)导致某些字节序列丢位;②响应在中间被截断,恰好在多字节字符的中间位置被切断,解码后变成残缺序列。标准 JSON 是 UTF-8 且字符串内可直接放中文/emoji(不转义也能解),所以不必为『有中文』本身担心。修复:确认响应按 UTF-8 完整接收,用 'JSON 校验' 定位到确切的字节偏移,再向前看是哪个多字节字符被切开。

← 返回博客首页