看到 JSON 解析报错,大部分人第一反应是去检查 JSON 格式有没有写错。但很多时候,问题根本不在 JSON 本身——而是你传进去的根本就不是 JSON。
这篇文章按报错信息分类,每种告诉你它实际在说什么、根因在哪、怎么修。
Unexpected token '<', "<!DOCTYPE "... is not valid JSON
这是最常见的一种,几乎每个前端开发者都遇到过。
它的意思不是"你的 JSON 格式不对",而是"你根本没收到 JSON,你收到的是一个 HTML 页面"。
为什么会收到 HTML?常见原因:
- 接口 URL 写错了,打到了一个不存在的路由,服务器返回了 404 页面
- 没有登录权限,服务器把你重定向到了登录页
- 服务器报错了,返回了 500 错误页面
- 本地开发时接口代理没配好,请求打到了前端开发服务器,返回了 index.html
// 出问题的代码
fetch('/api/user')
.then(res => res.json()) // 如果 res 是 HTML,这里直接报错
.then(data => console.log(data));
// 正确做法:先检查响应状态
fetch('/api/user')
.then(res => {
if (!res.ok) {
throw new Error(`HTTP error: ${res.status}`);
}
// 还是不放心,可以先看看 content-type
const contentType = res.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error(`Expected JSON, got: ${contentType}`);
}
return res.json();
})
.then(data => console.log(data))
.catch(err => console.error(err));
遇到这个报错,先不要看 JSON,先看网络请求。打开浏览器 DevTools → Network → 找到那个请求 → 看 Response 标签里实际返回了什么。大概率是一个 HTML 页面,里面有错误信息,那才是真正的线索。
Unexpected token 'u', "undefined" is not valid JSON
你调用了 JSON.parse(undefined)。
undefined 不是字符串,不是 JSON,传进去当然报错。通常发生在这几种情况:
// 情况1:变量没有初始化
let data;
JSON.parse(data); // data 是 undefined
// 情况2:从对象里取了一个不存在的字段
const response = { result: '{"name":"Alice"}' };
JSON.parse(response.data); // response.data 是 undefined,不是 result
// 情况3:localStorage 里没有存过这个 key
const saved = localStorage.getItem('user'); // 返回 null
JSON.parse(saved); // JSON.parse(null) 其实不报错,但如果 key 不存在...
// 某些情况下会拿到 undefined
修复方式就是在解析前做判断:
const raw = localStorage.getItem('user');
if (raw) {
const user = JSON.parse(raw);
}
// 或者更防御性的写法
function safeParse(str) {
if (!str || typeof str !== 'string') return null;
try {
return JSON.parse(str);
} catch {
return null;
}
}
SyntaxError: Unexpected end of JSON input
JSON 是完整的,但传进去之前被截断了。
JSON.parse('{"name":"Alice"'); // 缺少闭合的 }
JSON.parse(''); // 空字符串
JSON.parse('[1, 2, 3'); // 数组没有闭合
实际项目里,最常见的原因是网络请求中断——响应体只传了一半,连接就断了。另一种是后端在拼 JSON 字符串的时候(本来就不应该手拼)逻辑有 bug,字符串没有完整结束。
排查方式:打印一下收到的原始字符串,看看它在哪里结束的:
fetch('/api/data')
.then(res => res.text()) // 先用 text() 而不是 json()
.then(text => {
console.log('原始响应:', text);
console.log('最后20个字符:', text.slice(-20));
return JSON.parse(text);
});
TypeError: Converting circular structure to JSON
这个发生在 JSON.stringify() 的时候,不是 JSON.parse()。
循环引用是指对象直接或间接地引用了自己:
const obj = { name: 'Alice' };
obj.self = obj; // obj 引用了自己
JSON.stringify(obj); // TypeError: Converting circular structure to JSON
实际项目里最容易踩到这个坑的地方是把 Express 的 req 或 res 对象直接 stringify:
// 错误:req 内部有循环引用
app.post('/log', (req, res) => {
console.log(JSON.stringify(req)); // 报错
});
// 正确:只取你需要的字段
console.log(JSON.stringify({
method: req.method,
url: req.url,
body: req.body,
headers: req.headers
}));
如果确实需要序列化一个可能有循环引用的对象,可以用自定义 replacer:
function safeStringify(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) return '[Circular]';
seen.add(value);
}
return value;
});
}
JSON 里有 undefined、函数、Date 对象,序列化后消失或变形
JSON 不支持 JavaScript 的所有数据类型,有些值在 JSON.stringify() 时会被悄悄处理掉,不报错但结果不对:
const obj = {
name: 'Alice',
fn: function() {}, // 函数
undef: undefined, // undefined
date: new Date(), // Date 对象
nan: NaN, // NaN
inf: Infinity // Infinity
};
console.log(JSON.stringify(obj));
// {"name":"Alice","date":"2026-04-11T02:13:20.000Z","nan":null,"inf":null}
// fn 和 undef 直接消失了!date 变成了 ISO 字符串,NaN 和 Infinity 变成了 null
如果你的对象里有这些类型,序列化前要先处理:
// Date 对象:手动转成 ISO 字符串
const data = {
created_at: new Date().toISOString() // 明确控制格式
};
// undefined 值:改成 null
const data = {
middleName: null // 不要 undefined
};
排查思路总结
遇到 JSON 报错,按这个顺序来:
第一步:看原始内容,不要先看报错信息。 response.json() 改成 response.text() 先打印出来,确认收到的到底是什么。
第二步:看报错位置。 报错信息里会有 position 或行号,定位到那个字符附近看看是什么。
第三步:对着报错类型查原因。 < 开头是 HTML;undefined 是变量没初始化;end of input 是被截断了;circular structure 是循环引用。
格式问题(单引号、末尾逗号、键名没引号这类)粘到 JSON 格式化工具 里,智能修复会帮你定位并自动修正,不用自己数字符。



加载中...