Go 1.27 正式推出 encoding/json/v2 標準庫 JSON API 大幅改版

2026年11月4日,Go 團隊於官方博客宣布,encoding/json/v2 與 encoding/json/jsontext 兩個新套件已隨 Go 1.27 正式穩定並全面可用,結束自 Go 1.25 起的實驗階段[1]。這是 Go 標準庫多年來最大規模的 JSON 改動,同時涉及 API 設計、串流處理與預設行為。

另立 v2 的原因

Go 團隊指出,encoding/json 自 Go 1.0 之前已存在,多項行為缺陷與 API 限制屬現有設計的內在後果,在 Go 1 兼容承諾下幾乎無法修正。例如現有實作接受無效 UTF-8、接受重複成員名稱、把 nil slice 與 nil map 序列化為 null,以及以大小寫不敏感方式配對欄位名稱[1]。這些預設既可能造成資料損毀,亦曾被人利用作攻擊,官方引用 CVE-2017-12635 為例。因此團隊選擇開闢 v2 命名空間,而非在原有套件內加設 MarshalV2 一類並行 API。

預設行為的破壞性變更

v2 最重要的改動並非函數簽名,而是預設行為趨向嚴格:

  • 字串含無效 UTF-8 時回報錯誤,不再靜默替換為替代字元;
  • JSON 物件出現重複名稱時回報錯誤;
  • nil slice 與 nil map 分別序列化為空陣列 [] 與空物件 {},而非 null;
  • Go 型別若有結構性錯誤(例如格式錯誤的欄位標籤),執行時會回報錯誤;
  • 成員名稱配對改為區分大小寫,需要舊行為時可透過 MatchCaseInsensitiveNames 選項開啟[2]。

官方強調,這些差異並非向後兼容。下游若依賴 null 或重複名稱的處理方式,升級後可能出現行為改變,因此遷移必須配合測試[2]。

新 API 與串流處理

v2 將語法層與語意層分開:jsontext 套件只負責 JSON 語法,提供真正串流的 Encoder 與 Decoder,以及不需額外配置的 Token 與 Value 型別;json/v2 則負責 Go 值與 JSON 之間的對應[1]。新加入的 MarshalWrite 與 UnmarshalRead 可直接對 io.Writer 與 io.Reader 操作,MarshalJSONTo 與 UnmarshalJSONFrom 則讓自訂型別以串流方式實作序列化,避免舊有 MarshalJSON 介面必須先配置完整 []byte 再重新解析的成本。選項亦成為各函數的第一級參數,並可沿呼叫堆疊向下傳遞。

遷移路徑

官方提供三種遷移策略:風險承受能力高者可以一次過切換;較保守者可以先以 DefaultOptionsV1 呼叫 v2,再逐項關閉兼容選項;生產環境服務則可使用 jsonsplit 套件,同時以 v1 與 v2 序列化並回報差異,確認穩定後才切換至 v2[2]。官方提醒,同時執行兩次序列化會令成本約增加一倍,jsonsplit 亦提供取樣比例設定以控制開銷。

值得注意的是,encoding/json 不會消失,仍受 Go 1 兼容承諾保障,並與 v2 互相兼容;Go 1.27 新增的 JSON 結構標籤亦同時獲舊套件支援[2]。團隊表示,v2 的構思與開發歷時約六年,大部分貢獻者並非受僱於 Google[1]。

參考資料

[1] A new Go API for JSON(2026年11月4日)

[2] encoding/json/v2 Migration Guide

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

*