jsonpatch.mergepatch 必须传入 []byte,不能直接传 map 或 struct;null 表示删除字段而非设空;struct 字段需导出并正确加 json: tag;输入 json 应先用 json.valid() 校验。

Go 用 jsonpatch.MergePatch 合并 JSON 数据前必须解码为 map[string]interface{} 或 []interface{}
Go 标准库不直接支持 JSON Merge Patch(RFC 7386),得靠第三方库,最常用的是 github.com/evanphx/json-patch。它提供 jsonpatch.MergePatch 函数,但这个函数只接受原始字节([]byte)输入,且要求 base 和 patch 都是合法 JSON —— 它内部会把两者都解码成 Go 的通用结构(map[string]interface{} 或 []interface{})再合并。如果你传入已解码的 struct,会 panic。
常见错误现象:panic: interface conversion: interface {} is map[string]interface {}, not []uint8,这是因为误把 struct 或 map 直接传给了 jsonpatch.MergePatch。
- 正确做法:先用
json.Marshal把你的 base 和 patch 数据转成[]byte,再传给jsonpatch.MergePatch - 如果你已有
map[string]interface{},别试图绕过序列化 —— MergePatch 就是设计成“字节进、字节出”的,强行传 map 不仅错,还破坏语义 - 注意:空字段(
null)在 patch 中表示“删除该字段”,不是“设为空值”;这点和 JSON Patch(RFC 6902)不同,容易混淆
struct 转 JSON 字节时要小心字段导出与 tag
Go 的 json.Marshal 只序列化导出字段(首字母大写),且受 json: tag 控制。如果 base 是 struct,而你忘了加 tag 或字段未导出,json.Marshal 产出的 JSON 会丢失数据,导致 merge 结果意外为空或字段缺失。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 检查所有参与 merge 的字段是否导出(如
Name string✅,name string❌) - 确认
json:tag 没写错,比如json:"name,omitempty"在值为空时会跳过,可能让 patch 中的{"name": null}失效(因为 base 里根本没这个 key) - 如果 base struct 有嵌套 struct,确保嵌套字段也满足导出 + tag 规则,否则深层字段无法进入 JSON 流
patch 中的 null 表示删除,不是清空
这是 RFC 7386 的核心语义,也是最容易踩坑的地方。当你在 patch 里写 {"status": null},MergePatch 的行为是“从 base 中移除 status 字段”,而不是“把 status 设为 null”。如果 base 里本来就没有 status,那什么也不发生。
- 想设字段为
null(即保留 key,value 为 null),不能用 MergePatch —— 得换 JSON Patch(jsonpatch.CreatePatch+Apply)或者手动构造 - 想清空字符串字段(设为
""),patch 里写{"name": ""},不是{"name": null} - 对 slice 字段,
{"items": null}会删掉整个itemskey;若想清空 slice 内容,应写{"items": []}
生产环境建议加一层类型校验,别全信输入 JSON
jsonpatch.MergePatch 对非法 JSON 输入只返回 error,但不会告诉你哪一层结构崩了。如果 base 或 patch 来自外部(比如 HTTP 请求体),直接 merge 可能 panic 或静默失败(比如 patch 是 {"user": {"id": 123}},但 base 是数组,就会报错)。
- 上线前务必对输入做
json.Valid()检查,再调jsonpatch.MergePatch - 如果业务上 base 总是某个 struct 类型,建议先
json.Unmarshal到 struct,再json.Marshal回去 —— 这样既能验证格式,又能过滤掉 struct 里不存在的字段(防止恶意 patch 注入未知 key) - 注意性能:反复 marshal/unmarshal 有开销,高频场景可缓存 base 的字节形式,但得确保它不被并发修改
真正麻烦的从来不是怎么调用 jsonpatch.MergePatch,而是搞清楚你手里的数据到底是不是它想要的“纯 JSON 字节”,以及 patch 里那个 null 到底想干啥。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










