---
title: "Go 1.27 正式提供 encoding/json/v2　反序列化效能最多快十倍"
url: https://sammy.hk/go-json-v2-api/
author: Ethan
published: 2026-11-06T14:23:00+08:00
modified: 2026-11-06T14:23:00+08:00
description: "Go 團隊於 2026 年 11 月 4 日在官方博客公布，全新的 encoding/json/v2 與 encoding/json/jsontext 兩個套件已結束實驗階段，隨 Go 1.27 正式提供。這是 encoding/json 十多年來最大幅度的改動，官方強調舊有的 v1 API 會繼續支援，開發者毋須強制…"
categories: ["開放源碼"]
tags: [Go, JSON, "程式語言", "開發工具"]
source: https://sammy.hk
---
Go 團隊於 2026 年 11 月 4 日在官方博客公布，全新的 `encoding/json/v2` 與 `encoding/json/jsontext` 兩個套件已結束實驗階段，隨 Go 1.27 正式提供。這是 `encoding/json` 十多年來最大幅度的改動，官方強調舊有的 v1 API 會繼續支援，開發者毋須強制遷移\[1\]\[2\]。

## 語法層與語意層分家

新設計把 JSON 處理拆成兩層。`jsontext` 只負責語法，即按 RFC 8259 的文法讀寫 JSON token 與 value，不依賴反射；`json/v2` 則負責語意，把 JSON 值對應到 Go 型別。

`jsontext` 提供真正串流的 `Encoder` 與 `Decoder`，可以逐個 value 或 token 讀寫，寫入端亦有 `WriteToken`，補回 v1 只能讀 token、不能寫 token 的缺口。`json/v2` 的函式包括 `Marshal`、`MarshalWrite`、`MarshalEncode`、`Unmarshal`、`UnmarshalRead` 與 `UnmarshalDecode`，全部接受可變的 `Options` 參數，令設定可以直接傳入函式，亦可沿呼叫堆疊向下傳遞\[1\]。

型別自訂方面，除了沿用 v1 的 `Marshaler` 與 `Unmarshaler`，新增 `MarshalerTo` 與 `UnmarshalerFrom`，讓型別直接對 `Encoder` 或 `Decoder` 輸出，省去先配置 `[]byte` 再讓套件驗證與重新格式化的開銷。呼叫端亦可以用 `WithMarshalers`、`MarshalFunc` 等選項，為任意型別指定序列化方式，優先於型別自身的方法\[1\]。

## 預設行為變得更嚴格

v2 的預設行為與 v1 有若干部份不同，官方形容大部分可以透過 struct tag 或 option 還原\[1\]\[2\]：

- 遇到無效 UTF-8 會回報錯誤，而非默默接受造成資料損壞。
- JSON 物件出現重複成員名稱會回報錯誤。官方指出重複名稱在 RFC 8259 中沒有一致解釋，曾被利用作攻擊，例如 CVE-2017-12635。
- nil slice 與 nil map 分別序列化為 `[]` 與 `{}`，不再輸出 `null`。
- 反序列化改用區分大小寫的欄位配對，避免意外的欄位命中。
- `omitempty` 重新定義為「編碼後屬空值」才省略，即 `null`、`""`、`[]`、`{}`。
- 序列化 `time.Duration` 會回報錯誤，因為目前沒有公認的預設表示法，需由呼叫端指定。

## 效能與實際案例

官方基準顯示，v2 的 `Marshal` 效能與 v1 大致相若，有時略快、有時略慢；`Unmarshal` 則明顯較快，基準測試最多有十倍改善。若現有的 `Marshaler`、`Unmarshaler` 實作同時改為實作 `MarshalerTo`、`UnmarshalerFrom`，可以進一步受益於串流處理。

博客舉例，Kubernetes 有服務在 `UnmarshalJSON` 內遞迴解析 OpenAPI 規格，效能嚴重受損（kubernetes/kube-openapi 第 315 號議題），改用 `UnmarshalJSONFrom` 後改善達數個數量級。團隊表示會在 Go 1.28 繼續優化 v2 仍較 v1 慢的情境\[1\]。

## 遷移安排與相容性

Go 1.27 起，v1 的 `encoding/json` 在底層改由 v2 實作，並自動帶入一整組 v1 相容選項，因此現有程式行為不變，亦可即時享有 `MarshalJSONTo` 等新增能力。若遇到相容問題，可以在建置時設定 `GOEXPERIMENT=nojsonv2`，回復原本的 v1 實作，但官方預期此退出選項會在未來版本移除\[2\]。

遷移可以逐個呼叫點進行。開發者可以選擇全套 v2 行為但保留某一項舊行為，例如 `json.Marshal(..., json.DefaultOptionsV2(), jsontext.AllowDuplicateNames(true))`；亦可保留 v1 行為但關閉重複名稱，寫法是 `jsonv1.DefaultOptionsV1()` 配合 `jsontext.AllowDuplicateNames(false)`。官方另提供遷移指南與套件文件，列出每項行為差異對應的選項\[1\]。

這項改動由 2020 年底開始構思，經歷實驗階段與六年打磨，官方特別提到大部分開發者並非任職 Google，反映 Go 生態的協作模式\[1\]。

## 參考資料

\[1\] [A new Go API for JSON（2026-11-04）](https://go.dev/blog/jsonv2)

\[2\] [Go 1.27 Release Notes](https://go.dev/doc/go1.27)

### 相關文章：

1. [Go 1.27 正式推出 encoding/json/v2 標準庫 JSON API 大幅改版](https://sammy.hk/go-json-v2-stable/ "Go 1.27 正式推出 encoding/json/v2 標準庫 JSON API 大幅改版")
2. [Go 推出平台無關 SIMD 實驗：寫一次、跨架構加速](https://sammy.hk/go-%e6%8e%a8%e5%87%ba%e5%b9%b3%e5%8f%b0%e7%84%a1%e9%97%9c-simd-%e5%af%a6%e9%a9%97%ef%bc%9a%e5%af%ab%e4%b8%80%e6%ac%a1%e3%80%81%e8%b7%a8%e6%9e%b6%e6%a7%8b%e5%8a%a0%e9%80%9f/ "Go 推出平台無關 SIMD 實驗：寫一次、跨架構加速")
3. [Zig 0.17 發布：建置系統重新設計，增量編譯預期全面可用](https://sammy.hk/zig-0-17-%e7%99%bc%e5%b8%83%ef%bc%9a%e5%bb%ba%e7%bd%ae%e7%b3%bb%e7%b5%b1%e9%87%8d%e6%96%b0%e8%a8%ad%e8%a8%88%ef%bc%8c%e5%a2%9e%e9%87%8f%e7%b7%a8%e8%ad%af%e9%a0%90%e6%9c%9f%e5%85%a8%e9%9d%a2%e5%8f%af/ "Zig 0.17 發布：建置系統重新設計，增量編譯預期全面可用")
4. [Git 2.56 發布：新增 `git add --resolved` 與 `git refs` 擴充、衝突處理改善](https://sammy.hk/git-2-56-%e7%99%bc%e5%b8%83%ef%bc%9a%e6%96%b0%e5%a2%9e-git-add-resolved%e3%80%81git-refs-%e6%93%b4%e5%85%85%e8%88%87%e8%a1%9d%e7%aa%81%e8%99%95%e7%90%86%e6%94%b9%e5%96%84/ "Git 2.56 發布：新增 <code>git add --resolved</code> 與 <code>git refs</code> 擴充、衝突處理改善")
