Golang解析请求体报包含未知字段“password”错误如何解决?
问题根因与解决方案
根因分析
- 未知字段报错原因:你当前直接使用数据库映射结构体
models.User作为请求参数接收对象,它的Password字段JSON标签为"-",代表JSON序列化/反序列化全程忽略该字段;同时你开启了dec.DisallowUnknownFields()校验,要求请求JSON字段必须和结构体可反序列化字段完全匹配,请求携带的password字段无法被识别,因此抛出未知字段错误。 - base64报错原因:Go标准库
encoding/json反序列化[]byte类型字段时,默认要求输入是base64编码的字符串,你请求传的是明文密码abc12,不符合base64格式要求,因此解码失败。
最优解决方案
推荐使用请求DTO(数据传输对象) 分层接收参数,不要复用数据库映射结构体作为入参,既解决报错也符合架构规范:
步骤1:新增注册请求专用结构体
在models.go中新增专门用于接收注册请求的结构体:
// RegisterUserReq 用户注册请求参数结构体 type RegisterUserReq struct { FirstName string `json:"firstname"` LastName string `json:"lastname"` Email string `json:"email"` Phone string `json:"phone"` Password string `json:"password"` // 用string类型接收明文密码 }
原models.User的Password字段保持不变,继续用[]byte类型、JSON标签保持"-",保证数据库存哈希、序列化返回前端时不会泄露密码字段。
步骤2:修改注册接口逻辑
修改Handlers.go中的RegisterUser方法,用DTO接收参数后再调用入库逻辑:
func (app *appInjection) RegisterUser(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") // 替换原models.User,用专用请求结构体接收参数 var req models.RegisterUserReq err := app.decodeJSONBody(w, r, &req) if err != nil { var mr *malformedRequest if errors.As(err, &mr) { http.Error(w, mr.msg, mr.status) } else { log.Println(err.Error()) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } return } // 直接传请求中的明文密码,Insert方法内部会自动做哈希处理 uid, err := app.user.Insert( req.FirstName, req.LastName, req.Email, req.Phone, req.Password) if err != nil { log.Println(err.Error()) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } json.NewEncoder(w).Encode("Record Inserted") json.NewEncoder(w).Encode(uid) }
备选方案(不推荐)
如果不想新增DTO,也可以给models.User的Password字段实现自定义反序列化逻辑,绕开默认的base64解析规则:
func (u *User) UnmarshalJSON(data []byte) error { type Alias User aux := &struct { Password string `json:"password"` *Alias }{ Alias: (*Alias)(u), } if err := json.Unmarshal(data, &aux); err != nil { return err } u.Password = []byte(aux.Password) return nil }
该方案存在安全风险:models.User序列化返回给前端时会携带password字段,容易出现明文泄露问题,因此不推荐使用。
内容的提问来源于stack exchange,提问作者Patrick Cockrill
相关产品推荐
相关产品推荐

