multipart/form-data 顧名思義可以上傳多個form-data 並且用分隔字元進行分割,多用於檔案上傳
1. http multipart/form-data 請求範例
POST /handle HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 182537
Cache-Control: max-age=0
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Content-Disposition: form-data; name="submit-name"
jack
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Content-Disposition: form-data; name="file1"; filename="out.png"
Content-Type: image/png
binary-data
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Content-Disposition: form-data; name="file2"; filename="2.png"
Content-Type: image/png
binary-data-2
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig--
2. golang解析樣本
package main
import (
"bytes"
"net/http"
"io/ioutil"
"fmt"
"mime/multipart"
"io"
)
func main() {
bodyBuf := bytes.NewBuffer(nil)
bodyBuf.WriteString(`------WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Content-Disposition: form-data; name="submit-name"
xiongwei
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Content-Disposition: form-data; name="file1"; filename="out.png"
Content-Type: image/png
binary-data
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig
Content-Disposition: form-data; name="file2"; filename="2.png"
Content-Type: image/png
binary-data-2
------WebKitFormBoundaryWdDAe6hxfa4nl2Ig--`)
req := &http.Request{
Method: "POST",
Header: http.Header{"Content-Type": {`multipart/form-data; boundary=----WebKitFormBoundaryWdDAe6hxfa4nl2Ig`}},
Body: ioutil.NopCloser(bodyBuf),
}
getMultiPart3(req)
}
//通過r.ParseMultipartForm
func getMultiPart1(r *http.Request) {
/**
底層通過調用multipartReader.ReadForm來解析
如果檔案大小超過maxMemory,則使用臨時檔案來儲存multipart/form中檔案資料
*/
r.ParseMultipartForm(128)
fmt.Println("r.Form: ",r.Form)
fmt.Println("r.PostForm: ",r.PostForm)
fmt.Println("r.MultiPartForm:",r.MultipartForm)
getFormData(r.MultipartForm)
}
//通過MultipartReader
func getMultiPart2(r *http.Request)() {
mr,err := r.MultipartReader()
if err != nil{
fmt.Println("r.MultipartReader() err,",err)
return
}
form ,_ := mr.ReadForm(128)
getFormData(form)
}
//位元組解析multi-part
func getMultiPart3(r *http.Request)() {
mr,err := r.MultipartReader()
if err != nil{
fmt.Println("r.MultipartReader() err,",err)
return
}
for{
p ,err := mr.NextPart()
if err == io.EOF{
break
}
if err != nil{
fmt.Println("mr.NextPart() err,",err)
break
}
fmt.Println("part header:",p.Header)
formName := p.FormName()
fileName := p.FileName()
if formName != "" && fileName == ""{
formValue,_:= ioutil.ReadAll(p)
fmt.Printf("formName:%s,formValue:%s\n",formName,formValue)
}
if fileName != "" {
fileData,_:=ioutil.ReadAll(p)
fmt.Printf("fileName:%s,fileData:%s\n",fileName,fileData)
}
fmt.Println()
}
}
func getFormData(form *multipart.Form) {
//擷取 multi-part/form body中的form value
for k,v := range form.Value{
fmt.Println("value,k,v = ",k,",",v)
}
fmt.Println()
//擷取 multi-part/form中的檔案資料
for _,v := range form.File {
for i:=0 ;i < len(v);i++{
fmt.Println("file part ",i,"-->")
fmt.Println("fileName :",v[i].Filename)
fmt.Println("part-header:",v[i].Header)
f,_ := v[i].Open()
buf,_:= ioutil.ReadAll(f)
fmt.Println("file-content",string(buf))
fmt.Println()
}
}
}