Go 1.27 的 encoding/json/v2:默认更严,存量服务三条迁移路径
Go 1.27 引入两个新包:encoding/json/v2 和 encoding/json/jsontext。原有的 encoding/json 没有废弃,而是换成了 v2 实现。
两个新包的 API 形态
encoding/json/v2 是 encoding/json 的大改版,提供六个入口,全部接受可变参数 Options:
func Marshal(in any, opts ...Options) ([]byte, error)
func MarshalWrite(out io.Writer, in any, opts ...Options) error
func MarshalEncode(enc *jsontext.Encoder, in any, opts ...Options) error
func Unmarshal(in []byte, out any, opts ...Options) error
func UnmarshalRead(in io.Reader, out any, opts ...Options) error
func UnmarshalDecode(dec *jsontext.Decoder, out any, opts ...Options) error
encoding/json/jsontext 做更低层的语法处理。Encoder 和 Decoder 把 JSON 当作 Token 与 Value 的序列操作,内部维护状态机,保证产出或消费的序列是合法 JSON 文本。
v2 的默认行为比 v1 更严格
为了互操作性,v2 默认:
- 拒绝 JSON 字符串中的非法 UTF-8;
- 拒绝 JSON 对象内的重复成员名。
完整的差异清单和对应的调整选项在 v1 encoding/json 包文档里。
encoding/json 已由 v2 实现
encoding/json 的编组和解组行为保持不变,但错误信息的具体文本可能不同。这一点对做了错误字符串匹配的服务是实际风险,测试里的 err.Error() 断言需要复查。
性能方面:Marshal 大致与旧实现持平,Unmarshal 显著更快。
包内还新增了一批 Options,可以把 v2 配置成 v1 语义,从而不必一次性完成 API 迁移。v1 API 会继续支持,不强制迁移。
迁移取舍
三条路径,按改动成本排序:
- 完全不动:继续用 v1 API。行为保留,只需确认没有依赖错误文本。
- 用 Options 调回 v1 语义:仍走 v1 API,但通过新增的
Options对齐历史行为。适合暂时不想改调用点、又需要 v2 性能或逐渐收紧校验的场景。 - 迁到 v2 API:直接使用
Marshal/Unmarshal系列函数,显式传入Options表达策略。改动面最大,但语义最清楚。
如果新实现造成兼容问题,可以在构建时设置 GOEXPERIMENT=nojsonv2,恢复到原来的 v1 实现。这个回退开关预计在后续版本移除。
GOEXPERIMENT 期间被移除的项
从 GOEXPERIMENT 阶段到现在,encoding/json/v2 有几处删除:
format标签选项(#79071)unknown标签选项(#77271)DiscardUnknownMembers编组选项(#77271)SkipFunc哨兵错误(#74324)
同时有两处改名和行为调整:
inline标签选项改名为embed(#79985)string标签选项(#79065)与MatchCaseInsensitiveNames选项(CL 792780)的行为有更新
在 encoding/json/jsontext 中,数值类型的 Token 访问器改为同时返回错误(#77666)。原先直接取值的地方需要处理新增的 error。
背景和更多细节见 proposal issue;需要关闭新实现时,请提交 issue。
Go 博客索引中对应文章为 “A new Go API for JSON, 4 November 2026”。