HTML forms and Go
POST请求发送的键值对数据的格式是由HMTL form的content type指定的。在html中通过enctype指定如下:
<form action="/process" method="post" enctype="application/x-www-
form-urlencoded">
<input type="text" name="first_name"/>
<input type="text" name="last_name"/>
<input type="submit"/>
</form>
eenctype的默认值是application/x-www-form-urlencoded
,浏览器至少支持application/x-www-form-urlencoded和multipart/form-data。
如果设置enctype为application/x-www-form-urlencoded,浏览器会把HTML form数据编码为一个长的查询字符串,和url编码类似,用&来分割键值对,键值对之前用=分开:
first_name=sau%20sheong&last_name=chang
如果enctype为multipart/form-data,数据编码为下面的格式
------WebKitFormBoundaryMPNjKpeO9cLiocMw
Content-Disposition: form-data; name="first_name"
sau sheong
------WebKitFormBoundaryMPNjKpeO9cLiocMw
Content-Disposition: form-data; name="last_name"
chang
------WebKitFormBoundaryMPNjKpeO9cLiocMw--
form
访问Request中数据的通用方法是:
1.调用ParseForm或ParseMultipartForm解析Request。
2.访问对应的Form,PostForm, MultipartForm
e
c测试html,enctype =application/x-www-form-urlencoded
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Go Web Programming</title>
</head>
<body>
<form action=http://127.0.0.1:8089/process?hello=world&thread=123
method="post" enctype="application/x-www-form-urlencoded">
<input type="text" name="hello" value="sau sheong"/>
<input type="text" name="post" value="456"/>
<input type="submit"/>
</form>
</body>
</html>
服务器测试代码
func processf(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
Debug(w, r.Form)
Debug(w, r.PostForm)
Debug(r.Form["hello"])
Debug(r.FormValue("hello"))
Debug(r.PostFormValue("hello"))
// fmt.Fprintln(w, r.Form["hello"])
// fmt.Fprintln(w, r.FormValue("hello"))
// fmt.Fprintln(w, r.URL)
}
结果
364|&{0xc82018c100 0xc82019e540 0xc820156a00 false false 0xc820156a80 {0xc8200c7a00 map[] false false} map[] false 0 -1 0 false false [] 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] <nil>} map[hello:[sau sheong world] post:[456] thread:[123]]
365|&{0xc820196180 0xc8201a8620 0xc820194600 false false 0xc820194680 {0xc82018e5b0 map[] false false} map[] false 0 -1 0 false false [] 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] <nil>} map[hello:[sau sheong] post:[456]]
366|[sau sheong world]
367|sau sheong
368|sau sheong
可以看到如果form和url含有同样的key,会一起放在slice中,但是form的值优先于url。
postform只提供form的键值对,不包含url的。
把enctype改变为multipart/form-data
结果
364|&{0xc820196180 0xc820210e00 0xc8201f87c0 false false 0xc8201f8800 {0xc820232000 map[] false false} map[] false 0 -1 0 false false [] 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] <nil>} map[hello:[world] thread:[123]]
365|&{0xc820196180 0xc820210e00 0xc8201f87c0 false false 0xc8201f8800 {0xc820232000 map[] false false} map[] false 0 -1 0 false false [] 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] <nil>} map[]
366|[world]
367|world
368|
e
k可以看到只得到了url的键值对,由于PostForm只支持application/x-www-form-urlencoded,所以为空。
MultipartForm
d对于multipart/form-data要使用ParseMultipartForm解析。
r.ParseMultipartForm(1024)
fmt.Fprintln(w, r.MultipartForm)
MultipartForm不包含url键值对。
FormValue方法可以访问键值对无需调用ParseForm o或ParseMultipartForm,因为FormValue已经调用了。
FormValue只返回slice中的第一个值。u
如果enctype设置为multipart/form-data, FormValue和PostFormValue无法获取form的键值对,因为FormValue和PostFormValue对应的是Form和PostForm域,即使调用ParseMultipartForm,没有Form和PostForm域,所以无法获取。