JSON 解析報錯怎麼修:Unexpected token 逐條排查
結論:把瀏覽器、Node、Java、Python 的報錯原文翻譯成「第幾行第幾個字元出了什麼問題」,再按尾逗號、單引號、註釋、控制字元、BOM、截斷六個方向逐個排除。

結論:報 parse 錯誤時先看報錯的行列號定位第一個非法字元,再判斷是缺引號、缺逗號、尾逗號還是 BOM 或內容截斷,不要從頭重讀整段。
報錯資訊從來不告訴你「哪裡錯了」,它只告訴你「解析器走到哪走不下去了」。這兩個位置經常不是同一個地方。
一、先把報錯翻譯成座標
同一份壞 JSON,在不同語言裡報的錯完全不同,但都能換算成「第幾行、第幾個字元」:
| 環境 | 典型報錯 | 怎麼讀 |
|---|---|---|
| 瀏覽器 / Node | Unexpected token } in JSON at position 42 |
position 是從 0 開始的字元偏移,不是行號 |
| Node 20+ | Unexpected non-whitespace character after JSON at position 42 |
說明前半段合法,多餘內容在 42 之後 |
| Java Jackson | Unexpected character ('}' (code 125)): was expecting ... at [Source: (String)..."..." ; line: 3, column: 1] |
直接給了行列,最好用 |
| Python | json.decoder.JSONDecodeError: Expecting ',' delimiter: line 3 column 1 (char 42) |
char 是偏移,line/column 才是重點 |
| Go | invalid character '}' looking for beginning of object key string |
只給字元,需要自己回退定位 |
拿到 position 之後,把 JSON 粘進 JSON 線上解析,工具會直接把游標停在出錯位置並標紅行列號——這一步能省掉 90% 的肉眼數數。
二、六類高頻錯誤
1. 尾逗號
{
"name": "json",
"version": 1,
}
} 前多了一個逗號。JSON 規範不允許尾逗號,JavaScript 物件字面量允許,所以從程式碼裡複製出來的配置最容易帶這個。修復:刪掉最後一個逗號;如果這份資料本來就在 JS 檔案裡,改用 JSON5 轉換 而不是硬套 JSON。
2. 單引號與不加引號的鍵
{ 'name': 'json' }
{ name: "json" }
JSON 的字串只能用雙引號,鍵也必須是雙引號字串。這兩條是 JSON5 / JavaScript 的寬鬆語法,不是 JSON。字串內部的雙引號要寫成 \",反斜槓寫成 \\。
3. 註釋
{
// 超時時間,單位毫秒
"timeout": 3000
}
RFC 8259 的語法裡沒有註釋位置。要麼刪註釋,要麼改存 .jsonc / .json5 並用支援註釋的解析器。各種「註釋方案」的取捨見 JSON 註釋怎麼寫。
4. 字串裡的裸換行與控制字元
{"sql": "SELECT *
FROM t"}
JSON 字串內不允許直接出現換行、製表符和 U+0000–U+001F 控制字元,必須寫成 \n、\t、\u0009。多行文字塞進 JSON 時,先在編輯器裡做一次轉義,或者用 JSON 壓縮與轉義 統一處理。
5. BOM 頭
Windows 記事本儲存的 UTF-8 會帶 EF BB BF 三個位元組。JSON.parse 遇到 BOM 會直接報 Unexpected token,而肉眼完全看不出來。判斷方法:用十六進位制檢視檔案頭,或者把內容複製到線上工具裡看第一個字元是否顯示為 ``。修復:另存為「UTF-8 無 BOM」。
6. 內容被截斷
日誌只列印了前 4096 個字元、介面被閘道器截斷、下載中斷——這類報錯的特徵是「錯誤位置在末尾」且括號數量不匹配。先數括號:{、[ 的閉合數量對不上,就是截斷而不是語法錯。這時候不要修,去拿完整資料。
三、中文與轉義相關的兩類假故障
中文變成 \u4e2d\u6587:這是合法的 JSON 轉義,不是亂碼。解析後取值會還原成中文,只有直接看原始字串時才是 \u 形式。需要給人看的時候用 格式化工具 輸出即可;需要在 URL 或日誌裡保持中文,才需要關心轉義策略。
中文變成亂碼 涓枃:這是編碼問題,不是 JSON 問題。UTF-8 位元組被按 GBK 解碼就會出現這種「三個字元頂一個漢字」的規律性亂碼。檢查響應頭的 Content-Type: application/json; charset=utf-8,以及讀檔案時有沒有顯式指定 encoding='utf-8'。
四、五分鐘修復流程
- 貼進工具:先用 線上解析 定位第一個錯誤位置,一次只修一個;
- 修完再校驗:每修一處重新解析,避免一次改多處導致新錯誤覆蓋舊錯誤;
- 壓縮一次:用 壓縮 去掉空白再解析,能區分「結構錯」和「空白/換行引起的問題」;
- 結構對比:如果是改動後突然報錯,用 JSON 對比 和上一版比,差異往往就是那一個逗號;
- 欄位級校驗:語法透過但業務報錯(缺欄位、型別不對),是 JSON Schema 校驗 的範疇,不是語法問題。
五、為什麼「看起來一樣」的兩段 JSON 一段能解析
最常見的原因是不可見字元:全形逗號 ,、全形引號 “”、不換行空格 U+00A0、零寬空格 U+200B。它們和半形字元在螢幕上幾乎無法區分,但都不是 JSON 語法的一部分。
判斷辦法只有一個:把出錯字元前後的內容複製出來,逐位元組看碼點。在瀏覽器控制檯裡執行下面這段,能直接列出所有非 ASCII 且不屬於中文區間的字元:
[...text].filter((ch) => {
const code = ch.codePointAt(0);
return code > 127 && !(code >= 0x4e00 && code <= 0x9fff);
});
輸出裡出現 0x201c(左雙引號)、0xff0c(全形逗號)、0x00a0,就是它們的問題。
六、預防比修復便宜
- 配置類檔案在提交前跑一次解析校驗,CI 裡一行
node -e "JSON.parse(require('fs').readFileSync('config.json','utf8'))"就夠; - 介面返回統一用序列化庫生成,不要手寫拼接字串——手拼是尾逗號和漏引號的唯一來源;
- 日誌列印 JSON 時先
JSON.stringify,不要直接模板拼接,避免半截內容被當成完整報文。
常見問題
如何快速定位 JSON 語法錯誤的位置?
先拿解析器給出的 position 或 line/column,position 是從 0 開始的字元偏移,不是行號;Java Jackson 與 Python 的報告裡會直接給出行列。把 JSON 粘進 JSON 線上解析,工具會把游標停在出錯位置並標紅行列號,能省掉大部分肉眼數數。若錯誤出現在開頭,先檢查檔案頭是否帶 BOM,以及有沒有不可見字元。
為什麼從程式碼裡複製出來的配置最容易帶尾逗號?
JSON 規範不允許尾逗號,而 JavaScript 物件字面量允許,從 JS 程式碼裡複製出來的配置就很容易帶進這個逗號。修復只需刪掉最後一個逗號;如果這份資料本來就該留在 JS 檔案裡,改用 JSON5 轉換 比硬套 JSON 更合適。
是否可以把帶註解的配置檔案直接當 JSON 解析?
不行,RFC 8259 的語法裡沒有註解位置,直接解析會報錯。要麼刪掉註解,要麼改存 .jsonc / .json5 並使用支援註解的解析器。各種註解方案的取捨見 JSON 註解怎麼寫。