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