深入分析JavaScript中JSON.parse解析报错Unexpected token的核心成因,涵盖接口返回HTML错误页、单双引号混用、尾随逗号、二次解析对象及控制字符等典型场景,并提供切实可行的防御排查与修复方案。
JS解析JSON报错Unexpected token的常见原因与解决
时间:2026-10-30
浏览:125
文章目录
在 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 <。
解决办法:在解析响应体之前,严格校验 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)有着极度严苛的词法规则。
这种差异直接解释了下列经典报错:
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]":
- 解析器读取第 0 位字符
[,认为这是一个数组的开始。 - 解析器继续读取第 1 位字符
o,在数组的元素起始位置,o既不是数字、引号,也不是合法的字面量(如 true/false/null)。 - 于是立即抛出
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)或制表符,也会导致词法解析中断。
六、排查与定位四步法
遇到报错时,遵循规范的排查流程能够以最短路径解决问题。推荐按照以下四步顺序推进:
七、常见报错符号与根因速查
为了在实际编码中实现迅速应对,下表与图示总结了最典型的异常符号与直接对应的解决方案:
八、通用的健壮解析封装示例
在企业级开发中,任何来自用户输入、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 解析故障。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。