JSON.parse() 很嚴格。嚴格是資料交換的優點,但也意味著 JavaScript 物件字面量、日誌裡的「類 JSON」、和真正合法 JSON 之間的小差異,都會導致解析失敗。

最常見的 JSON 解析錯誤來自:

  • 尾逗號
  • 單引號
  • key 沒有雙引號
  • 註解
  • 複製了日誌前綴
  • 字串轉義錯誤
  • 介面回傳的是 HTML 或純文字,不是 JSON
  • 大整數解析後遺失精度

JSON 不是 JavaScript 物件字面量

下面是合法 JavaScript,但不是合法 JSON:

{
  name: 'Ada',
  active: true,
}

合法 JSON 必須使用雙引號包住 key 和字串,並且不能有尾逗號:

{
  "name": "Ada",
  "active": true
}

如果瀏覽器主控台、文件或後端日誌裡展示的「JSON」帶單引號或未加引號的 key,在嚴格解析前都應該當作類 JSON 文字。

常見 Unexpected token 原因

Unexpected token 表示解析器在某個位置遇到了不該出現的字元。

{"name": "Ada",}

"Ada" 後面的尾逗號非法。

{'name': 'Ada'}

單引號非法。

{name: "Ada"}

物件 key 必須使用雙引號。

{
  "name": "Ada" // user name
}

JSON 裡不能有註解。

先確認回應真的是 JSON

API 呼叫出現 JSON parse error 時,先看原始回應,不要先改解析程式碼。

常見意外情況:

  • 伺服端回傳了 HTML 錯誤頁
  • 代理回傳了登入頁
  • 介面回傳 204 No Content,body 為空
  • 後端在 JSON 前輸出了 warning
  • 回應被壓縮或編碼方式異常

前端可以暫時這樣除錯:

const text = await response.text()
console.log(text)
const data = JSON.parse(text)

如果第一個字元是 <,你很可能在解析 HTML。如果開頭是 Warning: 或堆疊資訊,應先修伺服端輸出。

先驗證,再格式化

格式化工具能讓合法 JSON 更易讀,但不能在沒有假設的情況下安全格式化非法 JSON。

用 JSON 工具定位:

  • 第一個非法字元
  • 錯誤行列
  • 括號是否匹配
  • 字串轉義是否正確
  • 屬性之間是否缺逗號

然後修源資料。不要依賴格式化工具自動「修復」正式環境 payload,除非你清楚它改了什麼。

正確處理轉義字元

JSON 字串裡,反斜線是轉義字元。

合法:

{
  "path": "C:\\\\Users\\\\Ada",
  "quote": "She said \\\"hello\\\""
}

非法:

{
  "path": "C:\Users\Ada"
}

如果資料來自某種程式語言的字串字面量,要注意可能有兩層轉義:語言字串一層,JSON 字串一層。

大整數可能遺失精度

JSON 支援數字,但 JavaScript 會把它解析成 Number。非常大的整數可能遺失精度。

有風險:

{
  "order_id": 12345678901234567890
}

更穩:

{
  "order_id": "12345678901234567890"
}

訂單號、支付流水、資料庫主鍵這類超過 JavaScript 安全整數範圍的 ID,通常應該序列化為字串。

排錯清單

JSON 解析失敗時:

  1. 複製原始回應或檔案內容。
  2. 確認開頭是 {["、數字、truefalsenull
  3. 檢查是否是 HTML、日誌前綴、warning 或空回應。
  4. 刪除尾逗號和註解。
  5. 只在確定是字串時,把單引號改成雙引號。
  6. 檢查字串裡的轉義。
  7. 大整數 ID 改用字串。

相關工具

JSON 格式化工具 校驗和格式化 payload。如果 JSON 裡包含 URL 欄位,先用 URL 編碼解碼工具 處理;如果包含 Base64 欄位,單獨用 Base64 工具 解碼,不要直接判斷整個 API 回應壞了。