在 Go 中, http.Request
上的函数可以从 URL
或 Body
中提取数据,通过 Form
字段、 PostForm
字段、 MultipartForm
字段可以提取表单数据。这一期我们就讲一讲这几个字段。
Form 字段
Form 里面的数据是键值对(key-value对)。
一般我们先调用 ParseForm
或 ParseMultipartForm
方法来解析 Request
。然后相应地访问 Form
字段、 PostForm
字段或 MultipartForm
字段来获取表单数据。
下面我们举个例子,首先创建一个 index.html 文件,主要用于创建表单,例子中创建了两个输入框,一个是用于输入 id
,另一个用于输入 name
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Go Web Form</title>
</head>
<body>
<form action="http://localhost:8080/" method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="id" />
<input type="text" name="name" />
<input type="submit" />
</form>
</body>
</html>
然后我们编写 main.go 文件,对提交的表单数据进行解析并输出:
package main
import (
"fmt"
"net/http"
)
func main() {
server := http.Server{
Addr: "localhost:8080",
Handler: nil,
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 解析
r.ParseForm()
// 输出
fmt.Fprintln(w, r.Form)
})
server.ListenAndServe()
}
运行程序,打开刚刚写好的 HTML 网页,在表单中输入数据,这里的 id
填入的是 123
而 name
填入的是 caizi
:
点击提交,转到 http://localhost:8080/
显示了刚刚我们表单输入的数据:
map[id:[123] name:[caizi]]
通过数据可以看出, r.Form
字段其实就是一个 map ,这里面有两个 key 分别是 id
和 name
,对应的值是一个字符串切片,分别是 [123]
和 [caizi]
。这里注意,每个 key 可以对应多个值,而且 map 里面数据的顺序是不一定的。
通过源码我们也可以知道, Form 是 url.Values
类型的:
Form url.Values
而 url.Values
实际上是一个 map ,其键是 string 类型的,而值是 []string 类型的:
type Values map[string][]string
PostForm 字段
如果我们只想得到某个 key 的 value ,可以使用 r.Form["key"]
,其返回含有一个元素的 slice
,例如刚刚上面的例子,调用 r.Form["name"]
会返回 ["caizi"]
。
上面我们也提到过,每个 key 可以对应多个 value ,如果表单和 URL 里有同样的 key ,那么它们都会放在一个 slice 里,但表单里的值会靠前,而 URL 的值会靠后。
还是上面那个例子,我们对 index.html 进行修改:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Go Web Form</title>
</head>
<body>
<form action="http://localhost:8080/?id=456" method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="id" />
<input type="text" name="name" />
<input type="submit" />
</form>
</body>
</html>
这里 URL 添加了参数, http://localhost:8080/?id=456
即 id=456
,同样打开网页填入刚刚的数据,会有下面的结果:
map[id:[123 456] name:[caizi]]
而如果只想要表单的键值对,而不想要 URL 的,可以使用 PostForm
字段。还是刚刚修改后的 index.html 文件,但把 main.go 中的 r.Form
修改成 r.PostForm
,运行后还是在表单中输入之前的数据,提交后如下:
map[id:[123] name:[caizi]]
可以看到只获取了表单的键值对。
但注意 PostForm
只支持 enctype
为 application/x-www-form-urlencoded
的情况。想要得到 multipart
键值对,必须使用 MultipartForm
字段
MultipartForm 字段
想要使用 MultipartForm 这个字段的话,首先需要调用 ParseMultipartForm
这个方法,这个方法需要一个参数,参数是需要读取数据的长度, int64
类型,单位是字节数。这个方法会在必要时自动调用 ParseForm
方法。MultipartForm
只包含表单的键值对。
该方法返回类型是一个 struct 而不是 map 。这个 struct 里有两个 map :
接下来我们把 index.html 中的 enctype
改成 multipart/form-data
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Go Web Form</title>
</head>
<body>
<form action="http://localhost:8080/?id=456" method="post" enctype="multipart/form-data">
<input type="text" name="id" />
<input type="text" name="name" />
<input type="submit" />
</form>
</body>
</html>
把 main.go 文件中的 r.ParseForm()
改成 r.ParseMultipartForm(1024)
,把 fmt.Fprintln(w, r.Form)
改成 fmt.Fprintln(w, r.MultipartForm)
。
package main
import (
"fmt"
"net/http"
)
func main() {
server := http.Server{
Addr: "localhost:8080",
Handler: nil,
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(1024)
fmt.Fprintln(w, r.MultipartForm)
})
server.ListenAndServe()
}
还是跟上面一样运行程序后打开 index.html 文件输入数据,提交后结果如下:
&{map[id:[123] name:[caizi]] map[]}
可以看到结果是一个结构体,里面有两个 map ,跟上面提到的一致。
👇希望对你有帮助,期待你的关注👇
联系客服