JS解析JSON报错Unexpected token的常见原因与解决

作者:纸飞机时间:2026-10-30 18:46:17浏览:128

深入分析JavaScript中JSON.parse解析报错Unexpected token的核心成因,涵盖接口返回HTML错误页、单双引号混用、尾随逗号、二次解析对象及控制字符等典型场景,并提供切实可行的防御排查与修复方案。

在 JavaScript 开发中,使用 JSON.parse() 或在网络请求中调用 response.json() 时,控制台抛出 SyntaxError: Unexpected token ... in JSON at position ... 属于极其高频的运行时异常。该错误的核心原因在于:解析器接收到的目标字符串不符合 ECMAScript 与 RFC 8259 严格定义的 JSON 文本规范。解决此问题的基本路径是精准定位 position 索引所指示的字符,识别输入源实际传递的内容形态,进而采取语法修正或前置校验策略。

一、报错信息的结构与定位逻辑

JavaScript 引擎抛出的 SyntaxError 通常包含两个关键线索:一个是触发非法的字符(Token),另一个是该字符在字符串中的下标索引(Position)。理解这两点能够直接指引排查方向:

  • Unexpected token < in JSON at position 0:说明字符串第 1 个字符就是左尖括号 <,绝大多数情况下是网络请求返回了 HTML 网页而非 JSON 格式。
  • Unexpected token ' in JSON at position 1:说明属性名或字符串值使用了单引号,违背了 JSON 规范对双引号的刚性约束。
  • Unexpected token o in JSON at position 1:说明传给 JSON.parse() 的变量本身已经是一个普通 JavaScript 对象。
  • Unexpected token } in JSON at position ...:通常表示对象内部最后一个属性后多写了尾随逗号。

当无法一眼看出问题时,可以通过简单的截取代码在控制台输出异常位置的前后文本,直观定位罪魁祸首:

function debugInvalidJson(rawStr, errorPosition) {
  const start = Math.max(0, errorPosition - 20);
  const end = Math.min(rawStr.length, errorPosition + 20);
  console.log("错误位置附近文本:", rawStr.slice(start, end));
  console.log("具体出错字符:", JSON.stringify(rawStr[errorPosition]));
}

二、原因一:接口返回 HTML 错误页(position 0 报错 <)

这是开发中最常见的场景。前端发起 Fetch 或 Axios 请求时,服务端因路由不存在返回 404,或者因未捕获异常返回 500。许多后端框架在出错时会默认返回一段 HTML 错误页面(以 <!DOCTYPE html> 或 <html> 开头)。

如果前端代码未校验 HTTP 状态码就直接调用 await response.json(),解析器把以 < 开头的 HTML 代码当成 JSON 解析,瞬间在 position 0 处抛出 Unexpected token <。

JS解析JSON报错Unexpected token的常见原因与解决
图 1:网络请求异常导致解析 HTML 报错的时序与防御流程图

解决办法:在解析响应体之前,严格校验 HTTP 响应状态码及 Content-Type 头信息,非正常状态下使用 response.text() 获取原始错误描述进行日志记录:

async function requestData(url) {
  const response = await fetch(url);
  
  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`HTTP ${response.status}: ${errorText.slice(0, 100)}`);
  }

  const contentType = response.headers.get("content-type");
  if (contentType && contentType.includes("application/json")) {
    return await response.json();
  }
  
  throw new Error("服务端返回的不是有效的 JSON 数据格式");
}

三、原因二:混淆 JS 对象字面量与 JSON 标准规范

在前端代码编写中,开发者经常把 JavaScript 对象的字面量写法与 JSON 字符串格式等同起来。在 JS 代码中,属性名不加引号、字符串使用单引号、或者存在尾随逗号都是合法的语法扩展;然而标准 JSON(RFC 8259)有着极度严苛的词法规则。

JS解析JSON报错Unexpected token的常见原因与解决
图 2:JS 对象字面量与 JSON 标准规范对比图

这种差异直接解释了下列经典报错:

  • JSON.parse("{'age': 18}"):由于使用单引号,在扫描到索引 1 的 ' 时立刻报 Unexpected token '。
  • JSON.parse('{age: 18}'):属性名缺少双引号,在扫描到字符 a 时立刻报 Unexpected token a。
  • JSON.parse('{"items": [1, 2, ],}'):由于数字 2 后面有多余逗号,扫描到 ] 时抛出 Unexpected token ]。

解决办法:不要使用手动字符串拼接的方式生成 JSON 数据,统一使用标准的 JSON.stringify() 输出:

// 错误做法:手动拼接易漏引号或引入单引号
const badStr = "{ 'id': " + id + ", 'title': '" + title + "' }";

// 正确做法:定义对象后使用原生方法序列化
const goodObj = { id: id, title: title };
const validJson = JSON.stringify(goodObj);
const parsed = JSON.parse(validJson);

四、原因三:对 Object 对象进行二次解析(position 1 报错 o)

在处理复杂组件传参或全局状态时,常常发生数据已经被上层逻辑或请求拦截器解析成了 Object,但下游代码仍然调用了一次 JSON.parse()。

当给 JSON.parse(input) 传入一个非字符串参数时,JavaScript 规范会首先执行隐式类型转换,调用 String(input)。对于一个普通对象,转换结果是固定字符串 "[object Object]":

  1. 解析器读取第 0 位字符 [,认为这是一个数组的开始。
  2. 解析器继续读取第 1 位字符 o,在数组的元素起始位置,o 既不是数字、引号,也不是合法的字面量(如 true/false/null)。
  3. 于是立即抛出 SyntaxError: Unexpected token o in JSON at position 1。
排查要点:只要看到报错提示为 Unexpected token o in JSON at position 1,99% 的概率是因为传入 JSON.parse() 的变量已经是 JavaScript 内存对象,而非 JSON 字符串。

解决办法:在解析前加入类型检测,确保只对字符串类型执行解析操作:

function parseSafe(data) {
  if (typeof data !== "string") {
    // 已经解析为对象则直接返回
    return data;
  }
  try {
    return JSON.parse(data);
  } catch (err) {
    console.error("JSON解析失败,原始入参为:", data);
    return null;
  }
}

五、原因四:不可见字符、BOM 头与未转义转义符

除了肉眼显而易见的语法偏差,还有两类隐蔽问题容易引发解析错误:

  • UTF-8 BOM 头(\uFEFF):从某些 Windows 编辑器或服务端导出文件时,文本首字节可能附带字节顺序标记 \uFEFF。在控制台直接打印时该字符不可见,但在 JSON.parse() 时会在 position 0 处报错 Unexpected token (显示为空白或特殊符号)。针对此情况,可在解析前过滤 str.replace(/^\uFEFF/, '')。
  • 未转义的反斜杠与换行符:JSON 中的换行符必须以字面量 \n 形式存在,若字符串中包含未经转义的原生换行(ASCII 10)或制表符,也会导致词法解析中断。

六、排查与定位四步法

遇到报错时,遵循规范的排查流程能够以最短路径解决问题。推荐按照以下四步顺序推进:

JS解析JSON报错Unexpected token的常见原因与解决
图 3:Unexpected token 异常排查四步流程

七、常见报错符号与根因速查

为了在实际编码中实现迅速应对,下表与图示总结了最典型的异常符号与直接对应的解决方案:

JS解析JSON报错Unexpected token的常见原因与解决
图 4:常见 Unexpected token 符号与对应根因速查

八、通用的健壮解析封装示例

在企业级开发中,任何来自用户输入、LocalStorage、Cookie 或第三方接口的字符串,均应被视为潜在不可信的输入。使用带有安全降级机制的包装函数,可以彻底阻断未捕获异常对整个应用界面的冲击:

/**
 * 健壮的 JSON 解析辅助函数
 * @param {string} text - 待解析的字符串
 * @param {*} fallbackValue - 解析失败时的兜底返回值
 * @returns {*} 解析后的结果或兜底值
 */
function safeJsonParse(text, fallbackValue = null) {
  if (typeof text !== "string") {
    return text ?? fallbackValue;
  }
  
  // 过滤不可见的 UTF-8 BOM 标头
  const cleanText = text.replace(/^\uFEFF/, "").trim();
  if (!cleanText) {
    return fallbackValue;
  }

  try {
    return JSON.parse(cleanText);
  } catch (error) {
    if (process.env.NODE_ENV !== "production") {
      console.warn("JSON解析异常:", error.message, "原始片段:", cleanText.slice(0, 80));
    }
    return fallbackValue;
  }
}

掌握了上述成因与排查路径后,面对 Unexpected token 错误时便无需茫然猜测。优先观察报错字符与位置、排查接口状态与请求头、保证严格使用双引号并不留尾随逗号,就能迅速解决绝大多数 JSON 解析故障。

作者最新文章
相关文章
更多