Go Request的Form、PostForm、MultipartForm、FormValue()、FormPostValue()、FileValue()区别
大家平时可能会使用HTML的Form(表单)
上传数据,特别是在上传二进制资源的时候(比如图片,视频等)。而我们一般会使用Form的两种内容格式(Content-Type),第一种是我们现在使用的比较多的multipart/form-data
(一般用来上传静态资源),还有一种是application/x-www-form-urlencoded
(和URL里的Query参数差不多)。这篇文章主要介绍一下这两种格式,还有在Go语言里面如何使用http.Request
对象操作这两种数据格式(有许多细微的差别)。
两种Form格式
application/x-www-form-urlencoded
根据这种格式的名字,我们可以推断出来它是使用URL的编码的,当然我们也可以通过指定Accept-Charset自定Form的编码规则。它只能接收简单结构的文本数据(无法像JSON一样多层嵌套),因此现在一般都使用application/json
格式代替它,下面是这种格式一个简单的例子:
/test1直接打印出Body里面的内容,而/test2则打印出Go各个application/x-www-form-urlencoded类型操作的结果
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
defer r.Body.Close()
if err != nil {
return
}
fmt.Println(string(body))
})
mux.HandleFunc("/test2", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
return
}
fmt.Println("Form: ", r.Form)
fmt.Println("PostForm: ", r.PostForm)
fmt.Println("FormValue(name): ", r.FormValue("name"))
fmt.Println("FormValue(age): ", r.FormValue("age"))
fmt.Println("PostFormValue(name):", r.PostFormValue("name"))
fmt.Println("PostFormValue(age): ", r.PostFormValue("age"))
})
server := &http.Server{
Addr: "127.0.0.1:8080",
Handler: mux,
}
server.ListenAndServe()
}
请求格式如下:
在使用test1时打印:可以看到,它就是对表格编码成URL的格式,所以它可以说是Body形式的Query参数
在使用test2时打印:可以看到Form会包含Body里面的和URL里面的,而PostForm只包含Body里面的内容,FormValue()会读取Body和URL里面的内容,而PostFormValue()只会读取Body里面的内容。
multipart/form-data
这个类型是我们目前经常使用的类型,它一般会被用来上传图片,视频等内容,而它的编码方式会为资源指定类型和文件名等内容,相对于application/x-www-form-urlencoded它的编码效率更低(因为它需要更多的字符表示不同类型的数据),但是它可以支持图片,视频等二进制格式内容,一般推荐在上传静态资源的时候使用它,下面是一个简单的例子:
同上面,/test1直接打印出Body里面的内容,而/test2则打印出Go各个multipart/form-data类型操作的结果
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/test1", func(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
defer r.Body.Close()
if err != nil {
return
}
fmt.Println(string(body))
})
mux.HandleFunc("/test2", func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(1024); err != nil {
return
}
fmt.Println("Form: ", r.Form)
fmt.Println("PostForm: ", r.PostForm)
fmt.Println("FormValue(name): ", r.FormValue("name"))
fmt.Println("FormValue(age): ", r.FormValue("age"))
fmt.Println("PostFormValue(name):", r.PostFormValue("name"))
fmt.Println("PostFormValue(age): ", r.PostFormValue("age"))
fmt.Println("MultipartForm: ", r.MultipartForm)
file, header, err := r.FormFile("avatar")
fmt.Println("FormFile(avatar): ", file, header, err)
})
server := &http.Server{
Addr: "127.0.0.1:8080",
Handler: mux,
}
server.ListenAndServe()
}
请求格式如下:
在使用test1时打印:可以看到是一种比较不节省空间的编码方式,通过----------------------------965042754073201157943416
间隔每个字段,然后在下面一行Content-Disposition: form-data; name="age"
中的form-data是multipart/form-data格式固定的,而name="age"表示字段名,对于二进制文件还会使用filename="381056168614065362.png"表示原始文件名(这样我们才能在服务器的接口拿到原始文件名)。对于文本字段,隔一行然后就是文本内容;对于二进制文件,隔一行然后是二进制内容。
在使用test2时打印:可以看到,适用于application/x-www-form-urlencoded的Go语言Request的操作也适用于multipart/form-data类型(所以multipart/form-data可以看作是支持二进制类型的application/x-www-form-urlencoded),而MultipartForm本身和PostForm一样只读取Body里面的内容,但是MultipartForm还会读取二进制的字段。而FormFile()就很明显只是获取Body里文件类型的内容。
总结
Go语言操作 | 解析操作 | 读取URL | 读取Body(表单) | 支持文本 | 支持二进制 |
---|---|---|---|---|---|
Form | ParseForm() | 是 | 是 | 是 | |
PostForm | ParseForm() | 是 | 是 | ||
FormValue() | 自动调用ParseForm() | 是 | 是 | 是 | |
PostFormValue() | 自动调用ParseForm() | 是 | 是 | ||
MultipartForm | ParseMultipartForm() | 是 | 是 | 是 | |
FormFile() | 自动调用ParseMultipartForm | 是 | 是 |
转载自:https://juejin.cn/post/7041166794941267998