土薯工具 Toolshu.com 登录 用户注册

JSON 解析报错看不懂,是因为你在看错误的地方

作者:bhnw 于 2026-04-27 15:20 发布 3次浏览 收藏 (0)

看到 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 的 reqres 对象直接 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 格式化工具 里,智能修复会帮你定位并自动修正,不用自己数字符。

发现周边 发现周边
评论区

加载中...