当前位置:首页 > 文章列表 > Golang > Go问答 > JSON 重复键解码时为什么只剩最后一个值?

JSON 重复键解码时为什么只剩最后一个值?

来源:17golang原创 2026-11-13 09:45:30 0浏览 收藏

我第一次遇到这个现象,是在排查一个“配置明明传了两次,程序却只认最后一次”的接口。原始 JSON 是 {"mode":"safe","mode":"fast"},解码到 Go 的 map[string]string 后只剩 fast。这不是 map 随机丢数据,而是 v1 encoding/json 按 JSON 成员出现顺序处理,重复键的后值覆盖先值。

如果重复键来自外部请求,不要把“最后一个值”当成业务规则。先保留原文并检测重复名;只有明确接受兼容语义时,才让默认解码继续。
要点速览
  • v1 encoding/json 允许重复键,简单字段通常由后值覆盖先值。
  • 结构体和嵌套对象可能出现“覆盖”与“合并”两种结果,不能只看 map 示例。
  • 安全边界上的 JSON 应在进入业务结构前检测重复键,并记录拒绝原因。

最小样例为什么只打印最后一个值

先不要从业务代码猜原因,用同一段输入分别解到 map 和结构体。下面的注释只解释关键断点,运行结果是文章中的示意输出,不是线上截图。

package main

import (
    "encoding/json"
    "fmt"
)

type Config struct {
    Mode string `json:"mode"`
}

func main() {
    raw := []byte(`{"mode":"safe","mode":"fast"}`)

    var values map[string]string
    // Unmarshal 按成员出现顺序写入 map,后一个 mode 会覆盖前一个。
    if err := json.Unmarshal(raw, &values); err != nil {
        panic(err) // 示例直接终止;服务代码应返回可定位的输入错误。
    }

    var cfg Config
    // 结构体字段也按同一顺序匹配,最后一次赋值保留下来。
    if err := json.Unmarshal(raw, &cfg); err != nil {
        panic(err) // 真实接口应把错误和请求追踪号一起记录。
    }

    fmt.Println(values["mode"], cfg.Mode) // 示意输出:fast fast
}

关键点是“按顺序处理”,不是 Go map 的遍历顺序。JSON 对象里的两个 mode 已经在解码阶段落到同一个目标字段,后来的 fast 把先前的 safe 覆盖了。

Go encoding/json 重复键按输入顺序覆盖 map 和结构体字段的静态说明图
图1:重复键顺序说明图,展示同名成员从原始 JSON 进入 map 与结构体后由后值覆盖先值;这是原创静态说明图,不是运行截图。

map 覆盖和嵌套对象合并不是一回事

官方文档把重复键描述为“后值替换或合并先值”,具体表现取决于目标值类型。简单字符串、数字、布尔值最容易观察到覆盖;嵌套对象解到已有的 map 或结构体时,字段级处理可能让结果看起来像合并。

目标类型观察到的现象排查重点
map[string]string后一个同名字符串覆盖前一个检查原文顺序和上游拼装逻辑
结构体字段同一字段后赋值保留确认 json tag 和大小写匹配
嵌套对象不同子字段可能继续存在不要把“合并”误判为安全去重

因此,看到“只剩最后一个值”时,先把目标类型、JSON tag、嵌套层级和重复键的出现顺序一起记下来。只打印 map,无法证明所有目标类型都只会简单覆盖。

进入业务前怎样把重复键变成明确错误

如果 JSON 来自浏览器、合作方或消息队列,重复键可能是上游拼接错误,也可能让不同解析器得出不同业务结果。更稳妥的做法是先保留原文,在语法校验通过后扫描每个对象的成员名;发现同一对象内重复名就拒绝,不把“最后值”交给权限、金额或路由逻辑。

工程上可以把“重复键检测”放在 HTTP 入站层或消息反序列化层,并把对象路径、键名、请求追踪号写入审计日志。日志不要记录完整敏感 payload,只记录足以定位的摘要。

Go JSON 入站层保留原文并检测重复键后再进入业务结构的防护边界说明图
图2:入站防护边界说明图,展示原文保留、重复名检测、审计拒绝和业务解码的关系;这是原创静态说明图,不是运行截图。

兼容输入与不可信输入应该分开处理

内部旧接口如果已经约定“后值生效”,可以继续使用 v1 默认行为,但应在协议文档里写清楚,并增加重复键测试。外部不可信输入则不建议依赖解析器差异。Go 的 JSON v2 方向已经提供拒绝重复名的选项和错误类型,但是否采用要看项目版本、实验特性和依赖约束;不能因为看到新 API 就直接替换生产解码器。

  • 兼容场景:保留原文、记录重复键计数,并让调用方逐步修复。
  • 安全场景:重复键直接返回 400 或消息进入隔离队列。
  • 审计场景:保存键名与对象路径,不把敏感值写入日志。

我的判断是:只要同一字段会影响权限、金额、状态迁移或下游签名,就把重复键视为输入错误,而不是一种“最后写入获胜”的方便语法。

相关问题

JSON 重复键是合法还是非法?

JSON 标准没有规定重复成员名必须采用哪一种解释,不同实现可以拒绝、覆盖或合并。Go v1 默认接受,协议边界应自行规定。

为什么改成结构体后结果仍然是最后一个值?

因为结构体字段也按输入顺序匹配;同名字段的后一次解码会覆盖先前赋值。需要检查的是原文和字段匹配,不是 map 遍历。

只用 json.Valid 能检测重复键吗?

不能。json.Valid 只判断语法是否有效;重复键在 v1 语法层面可以被接受,需额外做成员名扫描或使用明确拒绝重复名的解码策略。

排查这类问题时,保留原文是第一步,确认目标类型是第二步,最后才决定兼容还是拒绝。这样能把“少了一个值”的现象还原成可解释、可测试的输入规则。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
json.Marshal 为什么忽略未导出的字段json.Marshal 为什么忽略未导出的字段
上一篇
json.Marshal 为什么忽略未导出的字段
time.Parse 解析带中文时区为什么失败
下一篇
time.Parse 解析带中文时区为什么失败
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1010次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1014次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1139次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1108次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    954次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码