如何在 Go (Golang) 中将表单数据检索为地图(如 PHP 和 Ruby)

新手上路,请多包涵

我是一名 PHP 开发人员。但目前正在转向 Golang ……我正在尝试从表单(Post 方法)中检索数据:

 <!-- A really SIMPLE form -->
<form class="" action="/Contact" method="post">
  <input type="text" name="Contact[Name]" value="Something">
  <input type="text" name="Contact[Email]" value="Else">
  <textarea name="Contact[Message]">For this message</textarea>
  <button type="submit">Submit</button>
</form>

在 PHP 中,我会简单地使用它来获取数据:

 <?php
   print_r($_POST["Contact"])
?>
// Output would be something like this:
Array
(
    [Name] => Something
    [Email] => Else
    [Message] => For this message
)

但是在进行中……要么我一个一个地得到,要么整个事情而不是像 PHP 这样的 Contact[] 数组

我想到了 2 个解决方案:

1)一一获取:

 // r := *http.Request
err := r.ParseForm()

if err != nil {
    w.Write([]byte(err.Error()))
    return
}

contact := make(map[string]string)

contact["Name"] = r.PostFormValue("Contact[Name]")
contact["Email"] = r.PostFormValue("Contact[Email]")
contact["Message"] = r.PostFormValue("Contact[Message]")

fmt.Println(contact)

// Output
map[Name:Something Email:Else Message:For this Message]

请注意,映射键是整体的:“Contact [Name]”…

  1. Range whole map r.Form 并“解析|获取”前缀为“Contact[”的值,然后用空字符串替换“Contact[”和“]”,这样我就可以获得表单数组键PHP 示例

我自己完成了这项工作,但是……遍历整个表格可能不是一个好主意(?)

 // ContactPost process the form sent by the user
func ContactPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    err := r.ParseForm()

    if err != nil {
        w.Write([]byte(err.Error()))
        return
    }

    contact := make(map[string]string)

   for i := range r.Form {
       if strings.HasPrefix(i, "Contact[") {
           rp := strings.NewReplacer("Contact[", "", "]", "")
           contact[rp.Replace(i)] = r.Form.Get(i)
       }
   }

    w.Write([]byte(fmt.Sprint(contact)))
}
//Output
map[Name:Something Email:Else Message:For this Message]

两种解决方案都给我相同的输出……但在第二个例子中我不一定需要知道“Contact []”的键

我知道……我可能会忘记那个“表单数组”并在我的输入中使用 name="Email" 并一个一个地检索但是……我已经经历了一些场景,我使用一个包含超过 2 个数据数组,并对每个数组做不同的事情,比如 ORM

问题 1 :有没有更简单的方法让我的表单数组像 PHP 一样在 Golang 中作为实际地图?

问题 2 :我应该一个一个地检索数据(同样乏味,我可能会在某个时候更改表单数据并重新编译……)还是像我在第二个示例中所做的那样迭代整个过程。

抱歉我的英语不好…提前致谢!

原文由 David Lavieri 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 262
2 个回答

有没有更简单的方法让我的表单数组像 PHP 一样在 Golang 中作为实际地图?

您可以使用 PostForm http.Request 类型的成员。它是类型 url.Values 实际上是 (ta-da) a map[string][]string ,你可以这样对待。不过,您仍然需要先致电 req.ParseForm()

 if err := req.ParseForm(); err != nil {
    // handle error
}

for key, values := range req.PostForm {
    // [...]
}

请注意 PostForm字符串列表的 映射。这是因为理论上,每个字段都可以在 POST 正文中出现多次。 The PostFormValue() method handles this by implicitly returning the first of multiple values (meaning, when your POST body is &foo=bar&foo=baz , then req.PostFormValue("foo") will always return "bar" )。

另请注意 PostForm 永远不会包含 嵌套结构,就像您在 PHP 中使用的那样。由于 Go 是静态类型的,POST 表单值将 始终string (名称)到 []string (值/s)的映射。

就个人而言,我不会在 Go 应用程序中对 POST 字段名称使用方括号语法( contact[email] );这是一个特定于 PHP 的构造,无论如何,正如您已经注意到的那样,Go 对它的支持不是很好。

我应该一个一个地检索数据(同样乏味,我可能会在某个时候更改表单数据并重新编译……)还是像我在第二个示例中所做的那样迭代整个事情。

可能没有正确答案。如果您将 POST 字段映射到具有静态字段的结构,则必须在某些时候显式映射它们(或使用 reflect 来实现一些神奇的自动映射)。

原文由 helmbert 发布,翻译遵循 CC BY-SA 3.0 许可协议

我有一个类似的问题,所以我写了这个函数

func ParseFormCollection(r *http.Request, typeName string) []map[string]string {
    var result []map[string]string
    r.ParseForm()
    for key, values := range r.Form {
        re := regexp.MustCompile(typeName + "\\[([0-9]+)\\]\\[([a-zA-Z]+)\\]")
        matches := re.FindStringSubmatch(key)

        if len(matches) >= 3 {

            index, _ := strconv.Atoi(matches[1])

            for ; index >= len(result); {
                result = append(result, map[string]string{})
            }

            result[index][matches[2]] = values[0]
        }
    }
    return result
}

它将表单键值对的集合转换为字符串映射列表。例如,如果我有这样的表单数据:

 Contacts[0][Name] = Alice
Contacts[0][City] = Seattle
Contacts[1][Name] = Bob
Contacts[1][City] = Boston

我可以通过“联系人”的类型名称来调用我的函数:

 for _, contact := range ParseFormCollection(r, "Contacts") {
    // ...
}

它将返回两个地图对象的列表,每个地图都包含“名称”和“城市”的键。在 JSON 表示法中,它看起来像这样:

 [
  {
    "Name": "Alice",
    "City": "Seattle"
  },
  {
    "Name": "Bob",
    "City": "Boston"
  }
]

顺便说一句,这正是我在 ajax 请求中将数据发布到服务器的方式:

 $.ajax({
  method: "PUT",
  url: "/api/example/",
  dataType: "json",
  data: {
    Contacts: [
      {
        "Name": "Alice",
        "City": "Seattle"
      },
      {
        "Name": "Bob",
        "City": "Boston"
      }
    ]
  }
})

如果您的表单数据键结构与我的不完全匹配,那么您可以调整我正在使用的 Regex 以满足您的需要。

原文由 d4nt 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题