【问题标题】:traverse through multiple form values and put some of them inside struct slices遍历多个表单值并将其中一些放在结构切片中
【发布时间】:2017-07-28 05:10:34
【问题描述】:

我的情况是,我想将未知数量的输入值放入我的 Go 结构中,但只有其中一些会被放置在切片/数组中。这是 HTML 内容的 sn-p:

<form action="/" method="post">
...
<tbody>
    {{ range .users }}
    <tr>
        <td class="text-center">
            <img class="avatar" src="{{ .AvatarThumbnailURL }}">
            <input type="hidden" name="thumbnail" value="{{ .AvatarThumbnailURL }}">
        </td>
        <td>
            {{ .Username }}<input type="hidden" name="username" value="{{ .Username }}">
        </td>
        <td>
            {{ .Age }}<input type="hidden" name="age" value="{{ .Age }}">
        </td>
        <td>
            {{ .Email }}<input type="hidden" name="email" value="{{ .Email }}">
        </td>
    </tr>
    <input type="hidden" name="userid" value="{{ .UserID }}">
    {{end}}
</tbody>
...
{{ .csrfField }}

// submit button

</form>

{{ .csrfField }} 将生成隐藏输入。这部分工作正常。

现在的问题是如何在结构中获取这些数据?

假设我有以下结构:

type UserFormData struct {
   UserID int
   Username string
   AvatarThumbnailURL string
   Age int
   Email string
}

但是在我的 POST 函数中,我不知道有多少用户会通过表单提交。所以我想我必须这样做:

userFormData := make([]UserFormData, len(r.PostForm)/6) 

(除以6,因为有AvatarThumbnailURL、Username、Age、Email、UserID和csrfField)

然后可以像这样遍历r.PostForm:

i := 0
j := 0
for key, values := range r.PostForm {
    switch key {
    case "userid":
        userid, _ := strconv.Atoi(values[0])
        userFormData[j].UserID = userid
    case "thumbnail":
        userFormData[j].Thumbnail = values[0]
    // the other fields
    i++
    if i%6 == 0 {
        j++
    }
}

虽然这项工作很容易出现 indexoutofrange 错误,并且每当我进行更改时,我都必须计算将与表单一起发送的输入值的数量并更新(当前)“6”值。我毫不怀疑必须有一种非常非常好的方法来做到这一点,如果有人能指出我正确的方向,我将不胜感激:)

【问题讨论】:

  • 完全可能有更好的方法,但这至少可以避免使用幻数来知道有多少结构字段。 golang.org/pkg/reflect/#Value.NumField
  • 问题。如果你的范围超过.users,那你不知道会提交多少用户?您不能再包含一个隐藏字段,其中包含表单上有多少用户?
  • 无法保证浏览器会按照它们在 HTML 中出现的顺序提交表单字段,因此为了安全起见,您可能需要在字段名称中附加一个标识符以确保您可以正确相关的相关字段。

标签: html forms go


【解决方案1】:

您可以利用r.PostForm 实际上是一个映射,其中键是字段名称,值是字符串数组,因此您可以按照这些思路做一些事情(我没有测试它,但概念应该工作)。

我们遍历 "userid" 字段的所有值以了解有多少用户。此外,您可以使用append 将用户动态添加到切片中。

userFormData := []UserFormData{}
for i, userId := range r.PostForm["userid"] {
     user := UserFormData{
        UserID: userId,
        Thumbnail: r.PostForm["thumbnail"][i],
     }
     userFormData = append(userFormData, user)
}

【讨论】:

  • 哇,太好了,似乎工作得很好,非常感谢 :) 这种方法能保证用户 ID 始终与正确的缩略图、用户名、电子邮件等相关联吗?
  • 我认为在 HTML 生态系统中很难“保证”任何东西,你有很多不同的浏览器来实现,而且总是有一些极端情况。规范在这里讨论订单:w3.org/TR/html401/interact/forms.html#h-17.13.4.1。您应该对此进行测试,如果您想安全起见,可以在字段名称中包含一些数字后缀。
  • 经过一些测试,我还注意到,如果我有不同的地方具有相同的字段名称(例如,在范围循环之外输入 name="email"),那么数据很可能会被混合一起(当然应该不足为奇),但它似乎适用于所有主要浏览器,只要输入名称对于 rangeloop 是唯一的。我可能会考虑稍后添加后缀。再次感谢一切
猜你喜欢
  • 2018-12-09
  • 2019-07-20
  • 2018-06-13
  • 2014-04-02
  • 2021-06-16
  • 2017-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多