
当 Go 的 json.NewDecoder.Decode 无法正确解析 JSON 中的整数(如 score_to_pass、time_limit)导致字段值为 0 时,常见原因是结构体标签中误加了 string 选项——该选项会强制将 JSON 字符串转为整数,若传入的是纯数字而非字符串,则解码失败并保留零值。
当 go 的 `json.newdecoder.decode` 无法正确解析 json 中的整数(如 `score_to_pass`、`time_limit`)导致字段值为 0 时,常见原因是结构体标签中误加了 `string` 选项——该选项会强制将 json 字符串转为整数,若传入的是纯数字而非字符串,则解码失败并保留零值。
在 Go 的标准库 encoding/json 中,json:"field,string" 标签是一个特殊指令:它表示该字段期望接收 JSON 字符串形式的数值(例如 "32"),并在解码时自动调用 strconv.Atoi 等函数将其转换为对应整型。但如果你的请求体发送的是原生 JSON 数字(如 "score_to_pass": 32),而非字符串(如"score_to_pass": "32"),那么带,string的标签会导致解码失败——Go 会静默跳过该字段,保留结构体字段的零值(即int为0,bool为false`)。
你提供的原始结构体如下(已修正问题前):
type OnlineTestSet struct {
ID int `db:"id" json:"id"`
OnlineTestSubjectId int `db:"online_test_subject_id" json:"online_test_subject_id"`
Name string `db:"name" json:"name"`
ScoreToPass int `db:"score_to_pass" json:"score_to_pass"`
TimeLimit int `db:"time_limit" json:"time_limit"`
// ... 其他字段
}
✅ 正确做法是:移除所有 ,string 后缀,确保 JSON 字段名与结构体字段的 json 标签完全匹配,且类型一致。
同时,务必在解码后检查错误——你当前的代码忽略了 Decode 的返回值,这会掩盖关键问题:
func NewOnlineTest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
var jsonForm OnlineTestForm
// ✅ 必须检查解码错误!
if err := json.NewDecoder(r.Body).Decode(&jsonForm); err != nil {
http.Error(w, "Invalid JSON: "+err.Error(), http.StatusBadRequest)
return
}
if err := addNewOnlineTest(jsonForm.Form); err != nil {
log.Printf("Failed to save online test: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"success": true}`))
}
? 验证技巧:
- 使用
curl测试时,确保 payload 是合法 JSON(无多余逗号、引号闭合); - 在
Decode后打印jsonForm值(如log.Printf("%+v", jsonForm))可快速定位未填充字段; - 若 API 需兼容字符串/数字输入(如前端可能误传
"32"),应改用json.RawMessage+ 自定义UnmarshalJSON,而非全局加,string。
⚠️ 注意事项:
-
,string仅适用于int,uint,float64等数值类型,且仅当 JSON 中对应字段明确为字符串时才应使用; - 混淆使用会导致静默失败,调试困难;
- 数据库字段映射(如
db:"score_to_pass")与 JSON 解码无关,无需调整。
总结:Go 的 JSON 解码严格遵循类型契约。发送数字就用 json:"field",发送字符串才用 json:"field,string"。始终校验 Decode 错误,并结合日志快速定位字段绑定问题。











