DevToolBox免费
博客

JSON 解析错误:Unexpected Token — 如何查找并修复

7 分钟阅读作者 DevToolBox

如果你曾经在解析 JSON 时看到 SyntaxError: Unexpected token,你并不孤单。这是 JavaScript、Python、Go 及所有其他语言中最常见的 JSON 错误。好消息是:JSON 语法很简单,修复方法几乎总是以下十种常见错误之一。本指南展示了每种错误模式、准确的修复方法,以及防止再次发生的最佳调试工具。

1. "Unexpected Token" 在 JSON 中意味着什么

当 JSON 解析器遇到违反 JSON 规范的字符时,它会抛出一个错误,包含位置和有问题的字符。不同运行环境的错误消息略有不同:

JavaScript(浏览器/Node.js):

SyntaxError: Unexpected token ' in JSON at position 1

Python:

json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

Go:

invalid character '\'' looking for beginning of value

Java (Jackson):

com.fasterxml.jackson.core.JsonParseException: Unexpected character ('\'' (code 39)): was expecting double-quote to start field name

所有这些消息都意味着同一件事:你的 JSON 不是合法的。解析器在该位置发现了一个根据 JSON 规范(RFC 8259)不允许出现的字符。

JSON 比 JavaScript 对象字面量更严格。它要求键和字符串使用双引号,不允许尾随逗号,不支持注释,且只接受有限的值类型:字符串、数字、布尔值(true/false)、null、对象和数组。

2. 十大 JSON 语法错误(附修复前后对比)

错误 1:尾随逗号

JSON 不允许在对象或数组的最后一项之后有逗号。JavaScript 允许,这就是为什么这个错误如此常见。

错误写法:

{
  "name": "Alice",
  "age": 30,
}

错误信息:Unexpected token } in JSON at position 28

正确写法:

{
  "name": "Alice",
  "age": 30
}

错误 2:使用单引号代替双引号

JSON 要求所有字符串和键使用双引号(")。单引号(')不是合法的 JSON。

错误写法:

{'name': 'Alice', 'age': 30}

错误信息:Unexpected token ' in JSON at position 1

正确写法:

{"name": "Alice", "age": 30}

错误 3:未加引号的键

在 JavaScript 中,对象键不需要引号。在 JSON 中,每个键都必须是双引号字符串。

错误写法:

{name: "Alice", age: 30}

错误信息:Expected property name or '}' in JSON at position 2

正确写法:

{"name": "Alice", "age": 30}

错误 4:JSON 中的注释

JSON 规范不允许注释。不支持 ///* */#。如果需要注释,请使用 JSONC 或 JSON5(见第 6 节)。

错误写法:

{
  // This is a comment
  "name": "Alice",
  /* multi-line
     comment */
  "age": 30
}

错误信息:Unexpected token / in JSON at position 2

正确写法(删除注释):

{
  "name": "Alice",
  "age": 30
}

错误 5:undefined、NaN、Infinity

JSON 只支持 null 作为特殊值。undefinedNaNInfinity 是 JavaScript 特有的,不是合法的 JSON。

错误写法:

{
  "value": undefined,
  "score": NaN,
  "limit": Infinity
}

错误信息:Unexpected token u in JSON at position 12

正确写法:

{
  "value": null,
  "score": 0,
  "limit": 9999999
}

错误 6:多余或缺失的逗号

项目之间缺少逗号或有双逗号都会导致解析错误。

错误写法(缺少逗号):

{
  "name": "Alice"
  "age": 30
}

错误写法(双逗号):

{
  "name": "Alice",,
  "age": 30
}

错误信息:Expected ',' or '}' in JSON at position 18

正确写法:

{
  "name": "Alice",
  "age": 30
}

错误 7:括号类型错误(混淆 {} 和 [])

在需要花括号的地方使用了方括号(或反之)是常见的复制粘贴错误。

错误写法:

["name": "Alice", "age": 30]

错误信息:Expected property name or '}' in JSON at position 1

正确写法:

{"name": "Alice", "age": 30}

错误 8:BOM(字节顺序标记)字符

某些文本编辑器(特别是 Windows 上的)会在文件开头添加不可见的 UTF-8 BOM 字符(\uFEFF)。这个不可见字符会导致 JSON 解析失败。

错误示例(开头有不可见的 BOM):

\uFEFF{"name": "Alice"}   ← invisible BOM character before {

错误信息:Unexpected token \uFEFF in JSON at position 0

修复方法(解析前去除 BOM):

// JavaScript: strip BOM before parsing
const clean = jsonString.replace(/^\uFEFF/, '');
const data = JSON.parse(clean);

// Node.js: read file and strip BOM
const fs = require('fs');
const raw = fs.readFileSync('data.json', 'utf8');
const data = JSON.parse(raw.replace(/^\uFEFF/, ''));

错误 9:引号转义不正确

JSON 字符串内的双引号必须用反斜杠转义。字符串值中未转义的双引号会中断解析器。

错误写法:

{"message": "She said "hello" to me"}

错误信息:Unexpected token s in JSON at position 18

正确写法:

{"message": "She said \"hello\" to me"}

错误 10:特殊字符和控制字符

换行符、制表符和其他控制字符必须在 JSON 字符串中进行转义。字符串值中的原始换行符不是合法的。

错误写法(字符串中有原始换行符):

{"message": "line one
line two"}

错误信息:Unexpected token \n in JSON at position 22

正确写法(使用 \n 转义):

{"message": "line one\nline two"}

3. 如何调试 JSON 解析错误

当你遇到 JSON 解析错误时,以下工具和技巧将帮助你找到确切的问题。

浏览器控制台(Chrome/Firefox/Edge)

将你的 JSON 粘贴到浏览器控制台中以获取确切的错误位置:

// Paste this in your browser console:
try {
  JSON.parse('{"name": "Alice",}');
} catch (e) {
  console.error(e.message);
  // → "Expected double-quoted property name in JSON at position 17"
}

提示:Chrome DevTools 显示确切的位置编号。从开头数字符以找到有问题的字符。

Node.js

使用 try/catch 代码块获取详细的错误信息:

const fs = require('fs');

try {
  const raw = fs.readFileSync('config.json', 'utf8');
  const data = JSON.parse(raw);
} catch (err) {
  console.error('JSON parse failed:', err.message);
  // Shows: "Unexpected token , in JSON at position 42"

  // Extract the position and show surrounding context
  const pos = err.message.match(/position (\d+)/);
  if (pos) {
    const p = parseInt(pos[1]);
    const raw = fs.readFileSync('config.json', 'utf8');
    console.error('Context:', raw.substring(p - 20, p + 20));
    console.error('         ' + ' '.repeat(20) + '^');
  }
}

Python(json.loads)

Python 提供最有用的错误消息,包括行号和列号:

import json

raw = """{"name": "Alice", "age": 30,}"""

try:
    data = json.loads(raw)
except json.JSONDecodeError as e:
    print(f"Error: {e.msg}")
    print(f"Line: {e.lineno}, Column: {e.colno}")
    print(f"Character position: {e.pos}")
    # Output:
    # Error: Expecting property name enclosed in double quotes
    # Line: 1, Column: 29
    # Character position: 28

jq(命令行工具)

jq 是一个强大的命令行 JSON 处理器。将无效 JSON 传递给它,它会准确告诉你问题在哪里:

# Validate a JSON file
$ jq . config.json
# If valid: pretty-printed output
# If invalid: parse error at line X, column Y

# Validate inline JSON
$ echo '{"name": "Alice",}' | jq .
# parse error (Invalid numeric literal) at line 1, column 19

提示:如果你的 JSON 在变量中或来自 API,可以直接通过管道传递给 jq:

# Validate JSON from an API response
$ curl -s https://api.example.com/data | jq .

# Validate JSON from a shell variable
$ echo "$MY_JSON_VAR" | jq .

4. JSON 验证器:在错误进入生产环境之前捕获它们

预防胜于调试。在你的工作流中使用这些验证器。

在线验证器

粘贴你的 JSON,立即获得带有错误高亮的反馈:

  • DevToolBox JSON Formatter — 我们的内置工具可以实时验证、格式化和高亮 JSON 错误。
  • JSONLint.com — 经典的在线 JSON 验证器。
  • JSON Editor Online — 带有错误高亮的树形视图。

VS Code 内置验证

VS Code 自动验证 .json 文件并用红色波浪线显示错误。无需安装扩展。对于使用带注释的 JSON 的文件(如 tsconfig.json),VS Code 会自动使用 JSONC 解析器。

提示:使用"格式化文档"命令(Shift+Alt+F)自动格式化 JSON。如果格式化失败,说明你的 JSON 有语法错误。

命令行验证器

在终端或 CI 管道中验证 JSON:

# jq — validate and pretty-print
$ jq . data.json

# Python built-in
$ python -m json.tool data.json

# Node.js one-liner
$ node -e "JSON.parse(require('fs').readFileSync('data.json','utf8'))"

# Validate multiple files in a directory
$ for f in *.json; do echo -n "$f: "; jq . "$f" > /dev/null 2>&1 && echo "OK" || echo "INVALID"; done

jq . — 验证并美化打印。退出码 0 表示有效。

python -m json.tool — Python 内置,无需安装。

node -e — 使用 Node.js 快速验证。

5. 修复来自 API 的 JSON:处理边界情况

API 有时会返回不是合法 JSON 的数据。以下是常见的场景和修复方法。

API 返回 HTML 而不是 JSON

如果服务器返回 HTML 错误页面(404、500)而不是 JSON,JSON.parse() 会在遇到第一个 < 字符时失败。

修复方法:在解析之前检查 Content-Type 头和响应状态:

async function fetchJSON(url) {
  const response = await fetch(url);

  // Check status first
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }

  // Check Content-Type header
  const contentType = response.headers.get('content-type');
  if (!contentType || !contentType.includes('application/json')) {
    const text = await response.text();
    throw new Error(
      `Expected JSON but got ${contentType}: ${text.substring(0, 100)}...`
    );
  }

  return response.json();
}

JSONP 包装的响应

一些旧式 API 将 JSON 包装在函数调用中(callback({...}))。在解析前去除包装:

// JSONP response: callback({"name": "Alice", "age": 30})
function parseJSONP(jsonpString) {
  // Strip the function wrapper
  const match = jsonpString.match(/^[a-zA-Z_][a-zA-Z0-9_]*\((.*)\);?$/s);
  if (match) {
    return JSON.parse(match[1]);
  }
  // If no wrapper found, try parsing as regular JSON
  return JSON.parse(jsonpString);
}

拼接的 JSON / NDJSON

一些 API 流式传输多个以换行符分隔的 JSON 对象(NDJSON / JSON Lines)。需要逐行解析:

// NDJSON: one JSON object per line
const ndjson = `{"id":1,"name":"Alice"}
{"id":2,"name":"Bob"}
{"id":3,"name":"Charlie"}`;

const objects = ndjson
  .split('\n')
  .filter(line => line.trim())
  .map(line => JSON.parse(line));

console.log(objects);
// [{id:1,name:"Alice"}, {id:2,name:"Bob"}, {id:3,name:"Charlie"}]

被截断的 JSON 响应

网络超时或响应大小限制可能会在传输途中截断 JSON,导致无效的 JSON。在解析之前始终进行验证:

function safeJSONParse(text) {
  try {
    return { data: JSON.parse(text), error: null };
  } catch (err) {
    return {
      data: null,
      error: {
        message: err.message,
        position: err.message.match(/position (\d+)/)?.[1],
        preview: text.substring(0, 200) + (text.length > 200 ? '...' : ''),
      }
    };
  }
}

// Usage
const result = safeJSONParse(apiResponse);
if (result.error) {
  console.error('Invalid JSON:', result.error.message);
  console.error('First 200 chars:', result.error.preview);
}

6. JSON5 和 JSONC:何时使用宽松格式

有时严格的 JSON 对配置文件来说太痛苦了。有两种流行的替代方案:

JSONC(带注释的 JSON)

JSONC 允许在 JSON 中使用 ///* */ 注释。它被 VS Code 设置、tsconfig.json 和其他开发者工具使用。

JSONC 示例:

{
  // Database configuration
  "host": "localhost",
  "port": 5432,

  /* Credentials — loaded from env in production */
  "username": "dev_user",
  "password": "dev_pass",

  // Enable query logging in development
  "logging": true
}

在 Node.js 中解析 JSONC:

// Using the 'jsonc-parser' package (used by VS Code internally)
const { parse } = require('jsonc-parser');

const jsoncString = fs.readFileSync('config.jsonc', 'utf8');
const config = parse(jsoncString);

// Or strip comments manually with a regex (simplified, not production-ready)
function stripJsonComments(str) {
  return str
    .replace(/\/\/.*$/gm, '')          // Remove single-line comments
    .replace(/\/\*[\s\S]*?\*\//g, '');  // Remove multi-line comments
}

JSON5

JSON5 是 JSON 的超集,允许:单引号、不带引号的键、尾随逗号、注释、多行字符串、十六进制数字等。

JSON5 示例:

{
  // JSON5 allows all of this:
  unquotedKey: 'single quotes are fine',
  trailingComma: true,
  hexValue: 0xFF,
  leadingDot: .5,
  multiline: 'line one \
line two',
  infinity: Infinity,
  nan: NaN,
}

在 Node.js 中解析 JSON5:

// npm install json5
const JSON5 = require('json5');

const config = JSON5.parse(fs.readFileSync('config.json5', 'utf8'));

// JSON5 can also stringify
const str = JSON5.stringify(config, null, 2);

何时使用各种格式

格式适用场景不适用场景
JSONAPI 通信、数据交换、任何机器对机器格式需要人工频繁编辑的配置文件
JSONC配置文件(tsconfig.json、VS Code 设置)API 响应或数据交换
JSON5以开发者体验为优先的人工编写配置文件API 响应或需要标准 JSON 解析器的场景

7. 常见问题

为什么 JSON.parse() 对有效的 JavaScript 对象解析失败?

因为 JSON 不是 JavaScript。JSON 要求双引号的键和字符串,不允许尾随逗号,不支持注释、undefined、函数或任何 JavaScript 特有的语法。使用 JSON.stringify(obj) 将 JavaScript 对象转换为有效的 JSON。

如何找到 JSON 错误的准确位置?

大多数解析器在错误消息中包含字符位置(例如"at position 42")。在 VS Code 中,使用 Ctrl+G 跳转到行号,然后在该行上数字符。像 JSONLint 这样的在线验证器会直观地高亮显示确切的错误位置。Python 的 json 模块同时提供行号和列号。

可以在 JSON 中使用单引号吗?

不可以。JSON 规范(RFC 8259)要求所有字符串和属性名使用双引号。单引号不是合法的 JSON。如果你需要单引号支持,可以使用 JSON5,它同时允许单引号和双引号。

为什么我的 JSON 文件在 VS Code 中可以用,但在应用中失败?

VS Code 对许多文件类型使用 JSONC 解析器(带注释的 JSON),如 tsconfig.json.vscode/settings.json。你的应用程序可能使用的是严格的 JSON 解析器。删除所有注释和尾随逗号使其兼容严格 JSON,或者在你的应用中使用 JSONC/JSON5 解析器。

如何处理带有 BOM 字符的 JSON?

在解析之前去除 BOM。在 JavaScript 中:jsonString.replace(/^\uFEFF/, '')。在 Node.js 中,使用 UTF-8 编码读取文件并去除 BOM:fs.readFileSync(path, 'utf8').replace(/^\uFEFF/, '')。大多数现代编辑器都可以配置为保存不带 BOM 的文件。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON FormatterY{}JSON ↔ YAML Converter\Escape / UnescapeJSON Validator

相关文章

JSON vs YAML vs TOML:你应该用哪种配置格式?

比较 JSON、YAML 和 TOML 配置格式,了解语法、特性和优缺点,选择适合你项目的格式。

JSON 格式化与验证:在线美化、修复 JSON 完全指南

免费在线 JSON 格式化和验证工具。美化 JSON、查找语法错误,附 JavaScript 和 Python 代码示例。

JSON Schema 验证:类型、工具与最佳实践

关于 JSON Schema 验证的一切:从基本类型到高级模式、验证库以及与 TypeScript 和 API 的集成。