multipart/form-data
编码通常用于实现文件上传功能,这种功能需要用到file
类型的input
标签。代码清单4-5给出的就是之前展示过的客户端表单在实现了文件上传功能之后的样子,其中以加粗方式呈现的是新增或者经过修改的代码。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Go Web Programming< /title>
</head>
<body>
<form action="http://localhost:8080/process?hello=world&thread=123"
method="post" enctype="multipart/form-data">
<input type="text" name="hello" value="sau sheong"/>
<input type="text" name="post" value="456"/>
<input type="file" name="uploaded">
<input type="submit">
</form>
</body>
</html>
为了能够接收表单上传的文件,处理器函数也需要做相应的修改,具体见代码清单4-6。
代码清单4-6 通过MultipartForm
字段接收用户上传的文件
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func process(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(1024)
fileHeader := r.MultipartForm.File["uploaded"][0]
file, err := fileHeader.Open()
if err == nil {
data, err := ioutil.ReadAll(file)
if err == nil {
fmt.Fprintln(w, string(data))
}
}
}
func main() {
server := http.Server {
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/process",process)
server.ListenAndServe()
}
正如之前所说,服务器在处理文件上传时首先要做的就是执行ParseMultipartForm
方法,接着从MultipartForm
字段的File
字段里面取出文件头FileHeader
,然后通过调用文件头的Open
方法来打开文件。在此之后,服务器会将文件的内容读取到一个字节数组中,并将这个字节数组的内容打印出来。现在,如果我们向服务器上传一个纯文本文件,那么服务器将把这个文件的内容打印在浏览器上。
跟FormValue
方法和PostFormValue
方法类似,net/http
库也提供了一个FormFile
方法,它可以快速地获取被上传的文件:FormFile
方法在被调用时将返回给定键的第一个值,因此它在客户端只上传了一个文件的情况下,使用起来会非常方便。代码清单4-7展示了一个使用FormFile
方法的例子。
代码清单4-7 使用FormFile
方法获取被上传的文件
func process(w http.ResponseWriter, r *http.Request) {
file, _, err := r.FormFile("uploaded")
if err == nil {
data, err := ioutil.ReadAll(file)
if err == nil {
fmt.Fprintln(w, string(data))
}
}
}
正如代码所示,FormFile
方法将同时返回文件和文件头作为结果。用户在使用FormFile
方法时,将不再需要手动调用ParseMultipartForm
方法,只需要对返回的文件进行处理即可。