猿问

如何在 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

)

但是在进行中......要么我一一得到要么整个事情但不是 Contact[] 数组,例如 PHP


我想到了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]”...


2)范围整个地图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:我是应该一个一个地检索数据(很乏味,我可能会在某个时候更改表单数据并重新编译...)还是像我在第二个示例中所做的那样迭代整个过程。


对不起,我的英语不好......提前致谢!


人到中年有点甜
浏览 188回答 3
3回答

阿晨1998

有没有更简单的方法可以像 PHP 那样将我的表单数组作为 Golang 中的实际地图?您可以使用PostForm该http.Request类型的成员。它是一种类型url.Values——实际上是 (ta-da) a map[string][]string,你可以这样对待它。不过,您仍然需要先打电话req.ParseForm()。if err := req.ParseForm(); err != nil {&nbsp; &nbsp; // handle error}for key, values := range req.PostForm {&nbsp; &nbsp; // [...]}请注意,这PostForm是字符串列表的映射。这是因为理论上,每个字段都可以在 POST 正文中出现多次。该PostFormValue()方法通过隐式返回多个值中的第一个来处理此问题(意思是,当您的 POST 正文为 时&foo=bar&foo=baz,req.PostFormValue("foo")则将始终返回"bar")。另请注意,PostForm永远不会像您在 PHP 中使用的那样包含嵌套结构。由于 Go 是静态类型的,POST 表单值将始终是string(name) 到[]string(value/s)的映射。就个人而言,我不会contact[email]在 Go 应用程序中对 POST 字段名称使用括号语法 ( );这是一个 PHP 特定的构造,无论如何,正如您已经注意到的,Go 并没有很好地支持它。我是应该一个一个地检索数据(很乏味,我可能会在某个时候更改表单数据并重新编译...)还是像我在第二个示例中所做的那样迭代整个过程。可能没有正确的答案。如果您将 POST 字段映射到具有静态字段的结构,则必须在某个时候显式映射它们(或用于reflect实现一些神奇的自动映射)。

小怪兽爱吃肉

我有一个类似的问题,所以我写了这个函数func ParseFormCollection(r *http.Request, typeName string) []map[string]string {&nbsp; &nbsp; var result []map[string]string&nbsp; &nbsp; r.ParseForm()&nbsp; &nbsp; for key, values := range r.Form {&nbsp; &nbsp; &nbsp; &nbsp; re := regexp.MustCompile(typeName + "\\[([0-9]+)\\]\\[([a-zA-Z]+)\\]")&nbsp; &nbsp; &nbsp; &nbsp; matches := re.FindStringSubmatch(key)&nbsp; &nbsp; &nbsp; &nbsp; if len(matches) >= 3 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index, _ := strconv.Atoi(matches[1])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for ; index >= len(result); {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result = append(result, map[string]string{})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result[index][matches[2]] = values[0]&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return result}它将表单键值对的集合转换为字符串映射列表。例如,如果我有这样的表单数据:Contacts[0][Name] = AliceContacts[0][City] = SeattleContacts[1][Name] = BobContacts[1][City] = Boston我可以调用我的函数传递“联系人”的类型名称:for _, contact := range ParseFormCollection(r, "Contacts") {&nbsp; &nbsp; // ...}它将返回一个包含两个地图对象的列表,每个地图都包含“名称”和“城市”的键。在 JSON 表示法中,它看起来像这样:[&nbsp; {&nbsp; &nbsp; "Name": "Alice",&nbsp; &nbsp; "City": "Seattle"&nbsp; },&nbsp; {&nbsp; &nbsp; "Name": "Bob",&nbsp; &nbsp; "City": "Boston"&nbsp; }]顺便说一句,这正是我在 ajax 请求中将数据发布到服务器的方式:$.ajax({&nbsp; method: "PUT",&nbsp; url: "/api/example/",&nbsp; dataType: "json",&nbsp; data: {&nbsp; &nbsp; Contacts: [&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; "Name": "Alice",&nbsp; &nbsp; &nbsp; &nbsp; "City": "Seattle"&nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; "Name": "Bob",&nbsp; &nbsp; &nbsp; &nbsp; "City": "Boston"&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; ]&nbsp; }})如果您的表单数据键结构与我的不太匹配,那么您可能会调整我正在使用的正则表达式以满足您的需求。

万千封印

我有同样的问题。在我来自的 Ruby/Rails 世界中,数组表单参数的提交也是惯用的。但是,经过一些研究,看起来这并不是真正的“Go-way”。我一直在使用点前缀约定:contact.name,contact.email,等。func parseFormHandler(writer http.ResponseWriter, request *http.Request) {&nbsp; &nbsp; request.ParseForm()&nbsp; &nbsp; userParams := make(map[string]string)&nbsp; &nbsp; for key, _ := range request.Form {&nbsp; &nbsp; &nbsp; &nbsp; if strings.HasPrefix(key, "contact.") {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; userParams[string(key[8:])] = request.Form.Get(key)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Fprintf(writer, "%#v\n", userParams)}func main() {&nbsp; &nbsp; server := http.Server{Addr: ":8088"}&nbsp; &nbsp; http.HandleFunc("/", parseFormHandler)&nbsp; &nbsp; server.ListenAndServe()}运行此服务器,然后将其卷曲:$ curl -id "contact.name=Jeffrey%20Lebowski&contact.email=thedude@example.com&contact.message=I%20hate%20the%20Eagles,%20man." http://localhost:8088结果是:HTTP/1.1 200 OKDate: Thu, 12 May 2016 16:41:44 GMTContent-Length: 113Content-Type: text/plain; charset=utf-8map[string]string{"name":"Jeffrey Lebowski", "email":"thedude@example.com", "message":"I hate the Eagles, man."}使用大猩猩工具包您还可以使用Gorilla Toolkit 的 Schema Package将表单参数解析为结构体,如下所示:type Submission struct {&nbsp; &nbsp; Contact Contact}type Contact struct {&nbsp; &nbsp; Name&nbsp; &nbsp; string&nbsp; &nbsp; Email&nbsp; &nbsp;string&nbsp; &nbsp; Message string}func parseFormHandler(writer http.ResponseWriter, request *http.Request) {&nbsp; &nbsp; request.ParseForm()&nbsp; &nbsp; decoder := schema.NewDecoder()&nbsp; &nbsp; submission := new(Submission)&nbsp; &nbsp; err := decoder.Decode(submission, request.Form)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Fprintf(writer, "%#v\n", submission)}运行此服务器,然后将其卷曲:$ curl -id "Contact.Name=Jeffrey%20Lebowski&Contact.Email=thedude@example.com&Contact.Message=I%20hate%20the%20Eagles,%20man." http://localhost:8088结果是:HTTP/1.1 200 OKDate: Thu, 12 May 2016 17:03:38 GMTContent-Length: 128Content-Type: text/plain; charset=utf-8&main.Submission{Contact:main.Contact{Name:"Jeffrey Lebowski", Email:"thedude@example.com",&nbsp;
随时随地看视频慕课网APP

相关分类

Go
我要回答