字段废弃应改为未导出并加注释,重命名需双字段+自定义unmarshaljson,新增字段必带omitempty,dto须按版本独立声明。

字段废弃不能删,得改成未导出 + 注释标记
直接删除 struct 字段会让旧客户端反序列化时 panic,尤其当字段是必需非空类型(如 int、time.Time)时。Go 的 json 包遇到缺失字段会赋零值,但某些场景下零值本身是非法状态(比如 CreatedAt int64 变成 0),导致业务逻辑错乱。
正确做法是把字段名首字母小写,变成未导出字段,并保留 json tag:
// UserV1 保持兼容,v1 客户端仍能读到 old_name
type UserV1 struct {
ID int `json:"id"`
oldName string `json:"old_name,omitempty"` // 未导出,但 json 解析仍生效
FullName string `json:"full_name,omitempty`
}
// 在字段上方加明确注释
// deprecated: use FullName instead
- 未导出字段仍参与 JSON 编解码,只是不能被包外访问
- 注释必须写清楚替代字段,方便 IDE 跳转和团队协作
- 别依赖
json:",omitempty"隐藏字段——v2 客户端可能仍需读取该字段做迁移校验
重命名字段要双写 + 自定义 UnmarshalJSON
只改一个字段名,比如把 Name 改成 FullName,会导致 v1 客户端收不到 Name,v2 客户端又收不到 FullName——两边都断。
必须同时支持两个字段名,靠 UnmarshalJSON 做兜底解析:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
type UserV2 struct {
ID int `json:"id"`
Name string `json:"name,omitempty"` // v1 兼容字段
FullName string `json:"full_name,omitempty"` // v2 主字段
}
func (u *UserV2) UnmarshalJSON(data []byte) error {
type Alias UserV2 // 防止无限递归
aux := &struct {
Name *string `json:"name,omitempty"`
FullName *string `json:"full_name,omitempty"`
*Alias
}{
Alias: (*Alias)(u),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
if aux.Name != nil {
u.FullName = *aux.Name // 优先从 name 赋值
}
return nil
}
- 双字段声明是基础,
UnmarshalJSON是关键补丁 - 不推荐用
json_name(那是 protobuf 的概念),Go 的encoding/json不识别它 - 如果字段类型不同(如
string→int),就得在UnmarshalJSON里手动转换,不能依赖默认行为
新增字段必须带 omitempty + 合理零值
v1 客户端收到 v2 响应时,如果新增字段没设 omitempty,且值为零(比如 UpdatedAt time.Time 是零时间),就会被序列化成 "0001-01-01T00:00:00Z",前端可能误判为真实时间。
所有新增字段都要显式控制输出行为:
- 字符串字段:用
string `json:"field,omitempty"`,零值""不出现 - 数值字段:用指针类型(如
*int64)或加omitempty并确保业务上零值合法 - 时间字段:用
*time.Time或自定义类型实现MarshalJSON,避免零时间透出 - 切片字段:
[]string本身零值就是nil,omitempty可省略,但建议统一加上
DTO 必须按版本拆开,禁止跨版本嵌套
常见错误是让 UserV2 直接嵌入 UserV1:
type UserV2 struct {
UserV1 // ❌ 错误:v1 字段全被带进 v2 响应
NewField string `json:"new_field"`
}
这会导致 v1 的废弃字段(如 oldName)意外出现在 v2 响应里,违反契约隔离原则。
- 每个版本的 DTO 必须独立声明,哪怕字段完全一样
- 共用逻辑放 service 层,DTO 层只负责“当前版本该长什么样”
- 字段语义漂移比代码重复更危险——一个
status字段在 v1 是字符串,在 v2 变成枚举整数,嵌套后 JSON 序列化直接失败
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










