JSON 工具箱

JSON 解析報錯怎麼修:Unexpected token 逐條排查

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

入門約 12 分鐘發佈於 2026-10-30更新於 2026-11-01
JSON 解析報錯排查封面

結論:報 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'。

四、五分鐘修復流程

  1. 貼進工具:先用 線上解析 定位第一個錯誤位置,一次只修一個;
  2. 修完再校驗:每修一處重新解析,避免一次改多處導致新錯誤覆蓋舊錯誤;
  3. 壓縮一次:用 壓縮 去掉空白再解析,能區分「結構錯」和「空白/換行引起的問題」;
  4. 結構對比:如果是改動後突然報錯,用 JSON 對比 和上一版比,差異往往就是那一個逗號;
  5. 欄位級校驗:語法透過但業務報錯(缺欄位、型別不對),是 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 註解怎麼寫。