每個 JavaScript 開發者都看過這一幕:JSON.parse() 丟出一個 SyntaxError,應用程式就崩了。那段 JSON 來自一個 API、設定檔,或使用者剪貼簿 —— 就是解析不過去。本指南會逐步說明為什麼、實際情境裡壞 JSON 長什麼樣,以及如何優雅地處理 —— 從一個簡單的 try/catch 到自動修復。
1. JSON.parse() 為什麼會失敗
JSON 標準(RFC 8259)刻意嚴格。JSON.parse() 嚴格依規範實作 —— 任何偏離,不論多小,都會以一個沒有部分恢復的 SyntaxError 丟出:
try {
const data = JSON.parse('{ name: "Ada" }'); // 未加引號的 key
} catch (err) {
console.error(err.message);
// SyntaxError: Expected property name or '}' in JSON at position 2
}和瀏覽器解析 HTML(內建錯誤恢復模型)不同,JSON parser 是一道硬閘。嚴格解析是個特性:它逼生產方輸出乾淨資料。但當你無法控制資料來源時 —— LLM 輸出、手工編輯的設定檔、第三方 API —— 你就需要一套策略來應對這道閘關上的時候。
2. 最常見的壞 JSON 模式
在伸手抓修復工具之前,先認清你面對的是什麼。實務上幾乎所有壞 JSON 都落在以下某類:
單引號代替雙引號
// ❌ 非法 JSON
{ 'name': 'Ada Lovelace' }
// ✅ 合法
{ "name": "Ada Lovelace" }JavaScript 物件字面量接受單引號;JSON 不接受。開發者把一段物件字面量直接複製到 JSON 環境,就會反覆撞上這個錯誤。
尾隨逗號
// ❌ 非法 JSON
{
"name": "Ada",
"active": true, // 尾隨逗號
}
// ✅ 合法
{
"name": "Ada",
"active": true
}現代 JavaScript 允許陣列與物件中的尾隨逗號。JSON 不允許。這是手工編輯 JSON 檔案中最常見的單一錯誤。
未加引號的物件 key
// ❌ 非法 JSON
{ name: "Ada", score: 98 }
// ✅ 合法
{ "name": "Ada", "score": 98 }JavaScript 物件字面量不要求 key 加引號。JSON 要求所有 key 為雙引號字串,無例外。
JavaScript 註解
// ❌ 非法 JSON
{
// 這是使用者紀錄
"name": "Ada",
/* 2024 新增 */
"active": true
}JSON 沒有註解語法。註解有時會加到設定檔(JSONC —— 含註解的 JSON —— 是個流行擴展),但 JSON.parse() 會拒絕它們。
多行字串
// ❌ 非法 JSON
{
"description": "line one
line two"
}
// ✅ 合法 —— 轉義換行
{
"description": "line one\nline two"
}JSON 的字串值必須在單一行。字串內不允許字面換行;改用 \n 轉義序列。
NaN、Infinity 與 undefined
// ❌ 不是合法 JSON
{ "ratio": NaN, "limit": Infinity, "value": undefined }
// ✅ 合法替代
{ "ratio": null, "limit": 1e308, "value": null } 它們是合法 的 JavaScript 值,但不屬於 JSON 規範。JSON.stringify() 會悄悄轉換(NaN 與 Infinity 變成 null;undefined 屬性整個被丟掉),可能造成隱晦的往返 bug。
Python 字面量
// ❌ Python 風格 —— 非法 JSON
{ "active": True, "deleted": False, "value": None }
// ✅ 合法 JSON
{ "active": true, "deleted": false, "value": null } JSON 一開始就是為跨語言互通設計的。Python 那些首字母大寫的 True、False 與 None 是跨語言資料 bug 的常見來源。
3.「修復」與「解析」不是同一件事
務必分清兩種根本不同的操作:
- 嚴格解析 —— 驗證輸入完全是正確的 JSON、精準回報任何錯誤位置、拒絕任何偏離。當你能控制生產方並想強制契約時用。
- 修復解析 —— 用一組啟發式規則嘗試從語法不完美的輸入恢復出一個合法 JSON 值。當資料來自不可信或不精確的來源(LLM 輸出、使用者剪貼簿、舊服務)時用。
修復 parser 會做假設。遇到 True 它假設你想的是 true。遇到尾隨逗號就把它移除。對上面那些模式這些假設幾乎都正確 —— 但也可能默默掩蓋一份真正畸形的文件,讓「修復」改了你本來的意思。
正確的工具取決於情境。在 schema 驗證的 API 回應管線中,你想要嚴格解析,讓壞資料立刻浮上水面。在使用者貼一段 Slack 訊息裡複製來的 JSON 的開發者工具中,修復解析能省時。
值得認識的函式庫
兩個 npm 套件分擔了大部分重活,各有互補的取捨:
jsonrepair—— 一個寬容的修復 parser。把壞 JSON 餵給它,得到一段盡力修好的合法 字串。能處理上述模式(單引號、尾隨逗號、無引號 key、註解、Python 字面量、markdown 圍欄、未閉合括號、不完整輸入)。同步、零相依、體積小 —— 記憶體中有完整文件時最理想。clarinet—— SAX 風格的串流 JSON parser。當 JSON 分塊到達(資料流、大檔、LLM 逐 token 回應)且你想 key/value 一出現就反應,而非等完整文件,就用它。它對語法很嚴格,若來源不可靠,請搭配jsonrepair。
經驗法則:手上是一小段不可信 blob 就 修復;文件很大或漸進到達就 串流處理。
4. 捕捉錯誤並給使用者友善回饋
最低限度的可用模式是一個 try/catch。一律這麼做 —— 別讓 JSON.parse() 抛出未被捕捉的錯誤:
function safeParseJson(text) {
try {
return { ok: true, value: JSON.parse(text) };
} catch (err) {
return { ok: false, error: err.message };
}
}
const result = safeParseJson(userInput);
if (!result.ok) {
showError(`Could not parse JSON: ${result.error}`);
} JSON.parse() 的錯誤訊息因 JavaScript 引擎而異。V8(Node.js、Chrome)會附帶位置提示:
// V8 錯誤訊息
"Expected ',' or '}' after property value in JSON at position 42"
// Firefox SpiderMonkey
"JSON.parse: expected ',' or '}' after property value in object
at line 3 column 5 of the JSON data"位置資訊有用但綁特定引擎。若你需要跨環境可靠的行/欄回報,自寫一個遞迴下降 parser 能產出結構化錯誤,對使用者更友善。
5. 何時自動修復 vs. 請使用者確認
並非所有修復風險都相同。以下是一個實用啟發法:
- 可安全自動修復 —— 尾隨逗號、空白正規化、引號風格轉換、無引號 key、JavaScript 註解、Python 的 boolean/null 字面量。這些都是無語意歧義的機械轉換。
- 考慮詢問使用者 —— 結構性修復,例如自動閉合未閉合的物件或陣列(
{"name": "Ada"→{"name": "Ada"}),或剝除看似有意義的內容(移除看起來刻意寫的註解)。修復多半正確,但使用者可能想確認。 - 永遠標示、絕不默默修 —— 像
NaN → null這種型別轉換會改變資料值。要讓使用者看到改了什麼。
好的修復介面會顯示 diff:左側原始輸入、右側修復輸出。使用者在複製或提交結果前可確認修復正確。
6. 在瀏覽器處理 JSON 的隱私優勢
當你在瀏覽器中本機處理 JSON —— 使用已在此頁執行的 JavaScript 引擎 —— 資料從未離開使用者的電腦。這比開發者通常意識到的更重要:
- API key 與憑證 —— 開發者經常貼含機密的 JSON payload。伺服端工具會把每個請求記下來。
- PII 與健康資料 —— 沒有資料傳輸時,GDPR 與 HIPAA 合規會簡單得多。
- 公司內部資料 —— 許多安全政策禁止把內部資料貼到第三方 web 服務。
瀏覽器內處理帶來零風險的 JSON 修復:沒有伺服器、沒有日誌、沒有資料留存。運算在一個 <textarea> 與幾 KB 的 JavaScript 內進行。
常見問題
如何在 JavaScript 中處理 JSON.parse 錯誤?
把呼叫包進 try/catch,回傳結構化結果,而不是讓 SyntaxError 往上傳(見上方 safeParseJson helper)。對不可信輸入絕不要不加 guard 地呼叫 JSON.parse()。
有辦法自動解析壞 JSON 嗎?
有 —— 修復 parser 透過套用啟發式規則( 移除尾隨逗號、把單引號轉雙引號、把 True 轉小寫)從不完美輸入恢復出合法值。用於不可信來源(LLM 輸出、貼上文字);勿用於有契約驗證的 API 回應,那裡你想讓壞資料浮出。
我何時該修復 JSON vs. 拒絕它?
人貼了一段大致是 JSON 的東西或 LLM 產出時就修復;當你能控制生產方並想強制 schema 時就拒絕(嚴格解析)。像 NaN → null 這類型別轉換永遠要標示,絕不默默套用。
壞 JSON 最常見的成因是什麼?
把 JavaScript 物件字面量當成 JSON —— 單引號、無引號 key、尾隨逗號。見 JSON vs JavaScript 物件 與 [object Object] 與其他錯誤 中的語法錯誤參考。
7. 立刻試試 —— 把你的壞 JSON 貼進去
若你手上有畸形的 JSON 字串需要立刻修,JSON Fix 能處理上述所有模式 —— 單引號、尾隨逗號、無引號 key、Python 字面量、註解、markdown 程式碼圍欄等等。一切都在你的瀏覽器中執行,不會送往任何伺服器。
- JSON Fix —— 貼上壞 JSON、立刻拿回乾淨 JSON
- 線上修復 JSON —— 線上 JSON 修復工具如何運作及使用時機
- 修復 LLM 的 JSON 輸出 —— 針對 AI 產出 JSON 的專門指南
- JSON Formatter vs JSON Repair —— 何時使用何工具
- JSON Diff —— 並排對比兩份 JSON,看清楚改了什麼