
本文详解 go 中 rest api 解析 json 请求体时结构体字段为零值的原因,重点解决因 json 字段名未映射、数值类型不兼容(如负数赋给 uint)导致的解码失败问题,并提供可直接复用的修复方案。
本文详解 go 中 rest api 解析 json 请求体时结构体字段为零值的原因,重点解决因 json 字段名未映射、数值类型不兼容(如负数赋给 uint)导致的解码失败问题,并提供可直接复用的修复方案。
在 Go 的 HTTP 服务开发中,常见误区是误将 json.NewDecoder(r.Body) 的打印结果当作请求体内容——实际上,fmt.Printf("Request Body : ", decoder) 输出的是 *json.Decoder 内部指针和状态字段(如 r io.Reader),并非实际 JSON 数据。decoder 本身不持有解析后的值,只有调用 decoder.Decode(&v) 后,目标结构体才会被填充。
更关键的问题在于:你提供的 JSON 中 "rssi_max": -73.50 和 "rssi_min": -50.02 是负浮点数,而结构体定义使用了无符号整型:
type ApData struct {
ID int `db:"id"`
Mac string `db:"mac"`
RssiMax uint64 `db:"rssi_max"` // ❌ 无法接收负数
RssiMin uint16 `db:"rssi_min"` // ❌ 同样不支持负值
LocDefId uint64 `db:"loc_def_id"`
}
Go 的 json 包在解码时会尝试将 -73.50 转为 uint64,失败后保持字段零值(0),且不会报错(仅返回 nil 错误),导致静默失效。
✅ 正确做法如下:
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
- 为 JSON 字段添加 json 标签,确保键名匹配(JSON 默认按字段名匹配,但你的字段是 RssiMax,而 JSON 是 rssi_max);
- 使用有符号或浮点类型 接收负数(如 int64 或 float64);
- 解码后验证字段值,避免隐式零值入库。
修复后的结构体与处理器示例:
type ApData struct {
ID int `db:"id" json:"id,omitempty"`
Mac string `db:"mac" json:"mac"` // ✅ 显式映射
RssiMax float64 `db:"rssi_max" json:"rssi_max"` // ✅ 支持负浮点
RssiMin float64 `db:"rssi_min" json:"rssi_min"` // ✅ 同上
LocDefId uint64 `db:"loc_def_id" json:"loc_def_id"`
}
func InsertApData(w http.ResponseWriter, r *http.Request) {
// ⚠️ 必须关闭 Body,避免连接复用问题
defer r.Body.Close()
var apdata ApData
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&apdata); err != nil {
http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
return
}
// ✅ 验证关键字段(如 Mac 非空、RSSI 合理范围)
if apdata.Mac == "" {
http.Error(w, "mac is required", http.StatusBadRequest)
return
}
if apdata.RssiMax > 0 || apdata.RssiMin > 0 {
http.Error(w, "RSSI values must be negative", http.StatusBadRequest)
return
}
_, err := stmt.InsertApData.Exec(apdata.Mac, apdata.RssiMax, apdata.RssiMin, apdata.LocDefId)
if err != nil {
http.Error(w, "Database error: "+err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
}
? 注意事项:
- r.Body 是 io.ReadCloser,务必 defer r.Body.Close(),否则可能耗尽连接池;
- 使用 http.Error 统一返回带状态码的错误响应,而非仅 check()(该函数未定义,易掩盖问题);
- 若数据库字段必须为 uint,应在解码后做业务校验与转换(例如 if rssi
- 开发阶段建议用 log.Printf("Decoded: %+v", apdata) 打印结构体,而非 decoder 实例。
通过标签映射、类型对齐与显式错误处理,即可彻底解决“body 返回 nil”及字段值异常问题,确保 API 稳健可靠。










