看到 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 格式化工具 裏,智能修復會幫你定位並自動修正,不用自己數字符。



加載中...