Html 如何检索表单数据(作为数组)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34839811/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 18:48:27  来源:igfitidea点击:

How to retrieve Form data (as array)

htmlarraysformsgo

提问by David Lavieri

I'm a PHP Dev. But currently moving to Golang... I'm trying to retrieve data from a Form (Post method):

我是一名 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>

In PHP I would simple use this to get the data:

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

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

BUT in go... either I get one by one or the whole thing but not the Contact[] Array only such as PHP

但是在进行中...要么我一一得到,要么一举一动,但不是 Contact[] 数组,例如 PHP

I thought about 2 solutions:

我想到了2个解决方案:

1) Get one by one:

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]

Note that the map keys are the whole: "Contact[Name]"...

请注意,地图键是整体:“Contact[Name]”...

2) Range whole map r.Formand "parse|obtain" those values with Prefix "Contact[" and then replacing "Contact[" and "]" with empty string so I can get the Form array Key only such the PHP Example

2)范围整个地图r.Form和“解析|获得”这些值与前缀“Contact[”,然后用空字符串替换“Contact[”和“]”,这样我就可以得到表单数组键只有这样的PHP示例

I went for this work around by my own but... ranging over the whole form may not be a good idea (?)

我自己去完成了这项工作,但是......覆盖整个表格可能不是一个好主意(?)

// 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]

Both solutions give me the same output... But in the 2nd example I don't necessarily need to know the keys of "Contact[]"

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

I know... I may just forget about that "Form Array" and use name="Email"on my inputs and retrieve one by one but... I've passing through some scenarios where I use ONE form that contain more than 2 arrays of data and do different things with each one, like ORMs

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

Question 1: Is there a easier way to get my Form Array as an actual map in Golang like PHP does?

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

Question 2: Should I retrieve the data one by one (Tedious as much and I may change the Form data at some point and recompile...) or iterate the whole thing as I've done in the 2nd example.

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

Sorry for my bad English... Thanks in advance!

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

回答by helmbert

Is there a easier way to get my Form Array as an actual map in Golang like PHP does?

有没有更简单的方法可以像 PHP 那样将我的表单数组作为 Golang 中的实际地图?

You can use the PostFormmember of the http.Requesttype. It is of type url.Values-- which is actually (ta-da) a map[string][]string, and you can treat is as such. You'll still need to call req.ParseForm()first, though.

您可以使用PostFormhttp.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 {
    // [...]
}

Note that PostFormis a map of lists of strings. That's because in theory, each field could be present multiple times in the POST body. The PostFormValue()method handles this by implicitly returning the firstof multiple values (meaning, when your POST body is &foo=bar&foo=baz, then req.PostFormValue("foo")will always return "bar").

请注意,这PostForm字符串列表的映射。这是因为理论上,每个字段都可以在 POST 正文中出现多次。该PostFormValue()方法通过隐式返回多个值中的第一个来处理此问题(意思是,当您的 POST 正文为 时&foo=bar&foo=bazreq.PostFormValue("foo")则将始终返回"bar")。

Also note that PostFormwill never contain nested structureslike you are used from PHP. As Go is statically typed, a POST form value will alwaysbe a mapping of string(name) to []string(value/s).

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

Personally, I wouldn't use the bracket syntax (contact[email]) for POST field names in Go applications; that's a PHP specific construct, anyway and as you've already noticed, Go does not support it very well.

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

Should I retrieve the data one by one (Tedious as much and I may change the Form data at some point and recompile...) or iterate the whole thing as I've done in the 2nd example.

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

There's probably no correct answer for that. If you are mapping your POST fields to a struct with static fields, you'll have to explicitly map them at some point (or use reflectto implement some magical auto-mapping).

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

回答by d4nt

I had a similar problem, so I wrote this function

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

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
}

It turns a collection of form key value pairs into a list of string maps. For example, if I have form data like this:

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

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

I can call my function passing the typeName of "Contacts":

我可以调用我的函数,传递“联系人”的 typeName:

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

And it will return a list of two map objects, each map containing keys for "Name" and "City". In JSON notation, it would look like this:

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

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

Which incidentally, is exactly how I'm posting the data up to the server in an ajax request:

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

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

If your form data key structure doesn't quite match mine, then I you could probably adapt the Regex that I'm using to suit your needs.

如果您的表单数据键结构与我的不太匹配,那么您可能会调整我正在使用的正则表达式以满足您的需求。

回答by Elliot Larson

I had the same question. The submission of array form params is also idiomatic in the Ruby/Rails world where I'm coming from. But, after some research, it looks like this is not really the "Go-way".

我有同样的问题。在我来自的 Ruby/Rails 世界中,数组表单参数的提交也是惯用的。但是,经过一些研究,看起来这并不是真正的“Go-way”。

I've been using the dot prefix convention: contact.name, contact.email, etc.

我一直在使用点前缀约定:contact.namecontact.email,等。

func parseFormHandler(writer http.ResponseWriter, request *http.Request) {
    request.ParseForm()

    userParams := make(map[string]string)

    for key, _ := range request.Form {
        if strings.HasPrefix(key, "contact.") {
            userParams[string(key[8:])] = request.Form.Get(key)
        }
    }

    fmt.Fprintf(writer, "%#v\n", userParams)
}

func main() {
    server := http.Server{Addr: ":8088"}
    http.HandleFunc("/", parseFormHandler)
    server.ListenAndServe()
}

Running this server and then curling it:

运行此服务器,然后将其卷曲:

$ curl -id "contact.name=Jeffrey%20Lebowski&[email protected]&contact.message=I%20hate%20the%20Eagles,%20man." http://localhost:8088

Results in:

结果是:

HTTP/1.1 200 OK
Date: Thu, 12 May 2016 16:41:44 GMT
Content-Length: 113
Content-Type: text/plain; charset=utf-8

map[string]string{"name":"Jeffrey Lebowski", "email":"[email protected]", "message":"I hate the Eagles, man."}

Using the Gorilla Toolkit

使用大猩猩工具包

You can also use the Gorilla Toolkit's Schema Packageto parse the form params into a struct, like so:

您还可以使用Gorilla Toolkit 的 Schema Package将表单参数解析为结构体,如下所示:

type Submission struct {
    Contact Contact
}

type Contact struct {
    Name    string
    Email   string
    Message string
}

func parseFormHandler(writer http.ResponseWriter, request *http.Request) {
    request.ParseForm()

    decoder := schema.NewDecoder()
    submission := new(Submission)
    err := decoder.Decode(submission, request.Form)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Fprintf(writer, "%#v\n", submission)
}

Running this server and then curling it:

运行此服务器,然后将其卷曲:

$ curl -id "Contact.Name=Jeffrey%20Lebowski&[email protected]&Contact.Message=I%20hate%20the%20Eagles,%20man." http://localhost:8088

Results in:

结果是:

HTTP/1.1 200 OK
Date: Thu, 12 May 2016 17:03:38 GMT
Content-Length: 128
Content-Type: text/plain; charset=utf-8

&main.Submission{Contact:main.Contact{Name:"Jeffrey Lebowski", Email:"[email protected]", Message:"I hate the Eagles, man."}}