Golang 将 form-urlencoded 序列化为对象

分享于2022年07月17日 go go-gorm postgresql 问答
【问题标题】:Golang 将 form-urlencoded 序列化为对象(Golang serialize form-urlencoded to object)
【发布时间】:2022-01-15 12:19:57
【问题描述】:

我发出了一个发布请求,我将数据作为 JSON 发送,这段代码在数据库中创建了一个新行。

json.NewDecoder(r.Body).Decode(&user)
DB.Create(&user)
json.NewEncoder(w).Encode(user)

但是解析表单数据显示这个错误 Golang serialize form-urlencoded to object 我想这就是我读取每个单独值的方式

for key, value := range r.PostForm {
        fmt.Printf("Key:%s, Value:%s\n", key, value)
}

我的模型是这样的

type User struct {
    gorm.Model
    FirstName string `json:"firstname"`
    LastName  string `json:"lastname"`
    Email     string `json:"email"`
}

如何将其转换为用户并插入数据库?

  • json.NewDecoder(r.Body).Decode(&user) 是解码 JSON 请求正文的正确方法。那失败了吗?如果确实失败了,那么 Decode 返回的错误是什么?
  • 确实如此,我不想接受 JSON 请求正文,我正在以 application/x-www-form-urlencoded 的身份通过邮递员发送请求
  • u.FirstName = r.FormValue("firstname") 等等。
  • 需要解析一个 URL 编码的表单给用户

【解决方案1】:

另一种方法(有点过度设计,最好使用 r.FormValue ),如果您已经知道数据、类型等,则无需再次键入字段,例如 r.FormValue("firstname") 等。

func handleUser(w http.ResponseWriter, r *http.Request) {
    user := User{}
    userType := reflect.TypeOf(user)
    for i := 0; i < userType.NumField(); i++ {
        // Get the JSON tag of the field, use it for the r.FormValue
        f := userType.Field(i).Tag.Get("json")
        if f != "" {
            reflect.ValueOf(&user).Elem().FieldByName(
                userType.Field(i).Name).SetString(r.FormValue(f))
        }
    }
    // DB.Create(&user) need a reference to DB here.
    json.NewEncoder(w).Encode(user)
}

注意:这只是一个适用于字符串字段的示例,否则可能会因为调用 SetString 而引起恐慌。此外,一个字段可能不存在,并且在尝试在 FieldByName(... 中访问它时可能会出现恐慌,但我认为您的问题是针对这个不必键入每个字段的方向,因此将其作为示例。

正如 Cerise Limón 指出的那样,正确的做法是

func handleUser(w http.ResponseWriter, r *http.Request) {
    user := User{}
    user.FirstName = r.FormValue("firstname")
    user.LastName = r.FormValue("lastname")
    user.Email = r.FormValue("email")
    // DB.Create(&user) need a reference to DB here.
    json.NewEncoder(w).Encode(user)
}

请注意,如果您在多个地方执行此操作,您还可以添加一个使用表单填充用户的方法,例如

func (u *User) setFormData(r *http.Request) {
    u.FirstName = r.FormValue("firstname")
    u.LastName = r.FormValue("lastname")
    u.Email = r.FormValue("email")
}

然后像这样使用它

func handleUser(w http.ResponseWriter, r *http.Request) {
    user := User{}
    user.setFormData(r)
    // DB.Create(&user)
    json.NewEncoder(w).Encode(user)
}