beego 的 c.servejson() 默认启用零值过滤(0、""、nil、false 字段不输出),非 bug 而是设计;需用 c.servejson(false) 或原生 json.marshal() 绕过,且字段必须大写导出。

Beego 默认会丢掉零值字段,不是 bug 是设计
Beego 的 c.ServeJSON() 默认启用 json.Marshal() + 零值过滤(即字段为 0、""、nil、false 时直接不输出),这不是序列化失败,而是框架主动行为。它和结构体是否导出、是否有 json tag 无关,是 Beego 自己加的一层逻辑。
常见现象:结构体字段明明有值(比如 Age: 0、Status: ""),但返回 JSON 里直接消失;或数据库查出的 int 字段为 0,前端收不到该 key。
关键点:c.ServeJSON() 底层调用的是 json.Marshal(),但 Beego 在此之前做了零值裁剪 —— 这个动作不可跳过,除非你绕开它。
关闭零值过滤的两种可靠方式
必须显式关闭,否则所有零值字段都会被静默剔除:
- 方式一(推荐):在调用前设置
c.Data["json"] = mystruct后,立即加c.ServeJSON(false)—— 第二个参数false表示禁用零值过滤 - 方式二:改用原生
json.Marshal()+ 手动写响应体,例如:data, _ := json.Marshal(mystruct) c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json") c.Ctx.ResponseWriter.Write(data) - 注意:
c.ServeJSON(true)是默认行为(等价于无参调用),别误以为传true是“开启”什么功能
结构体字段小写导致整个字段消失,和零值过滤无关
如果字段首字母小写(如 name string),Go 的 json 包根本无法反射访问,json.Marshal() 返回结果里连 key 都不会出现 —— 这和 Beego 的零值过滤是两回事,但现象相似,容易混淆。
正确做法:
- 确保结构体字段首字母大写(
Name string) - 若需小写 JSON key,用
jsontag 显式声明:Name string `json:"name"` - 别依赖
form或ormtag 来控制 JSON 输出,它们互不影响
嵌套结构体或 map 字段为空时的行为差异
Beego 对嵌套结构体、map[string]interface{}、切片等类型的“空”判断更宽松:
-
map[string]interface{}值为nil会被删;但空 map(map[string]interface{}{})会保留为{} - 嵌套结构体字段为
nil指针时,整个字段被删;若为非 nil 空结构体(如&User{}),则按其内部字段是否零值再决定 - 切片为
nil被删;空切片([]string{})保留为[] - 这些行为在
c.ServeJSON(false)下仍保持原生json包语义,不会额外过滤
真正容易被忽略的是:零值过滤开关只作用于当前一次 ServeJSON 调用,不能全局配置;且一旦用了 json tag,就得同时兼顾大小写规则和零值语义 —— 少一个环节,字段就悄无声息地没了。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











