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 解析失敗時:
- 複製原始回應或檔案內容。
- 確認開頭是
{、[、"、數字、true、false或null。 - 檢查是否是 HTML、日誌前綴、warning 或空回應。
- 刪除尾逗號和註解。
- 只在確定是字串時,把單引號改成雙引號。
- 檢查字串裡的轉義。
- 大整數 ID 改用字串。
相關工具
用 JSON 格式化工具 校驗和格式化 payload。如果 JSON 裡包含 URL 欄位,先用 URL 編碼解碼工具 處理;如果包含 Base64 欄位,單獨用 Base64 工具 解碼,不要直接判斷整個 API 回應壞了。