Multipart File Upload

multipart/form-data 顾名思义可以上传多个form-data 并且用分隔符进行分割,多用于文件上传
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–



func (c *PostGetController) sendPostFormFile(url string, filename string)(error) {
body_buf := bytes.NewBufferString(“”)

body_writer := multipart.NewWriter(body_buf)

// boundary默认会提供一组随机数,也可以自己设置。
body_writer.SetBoundary(“Pp7Ye2EeWaFDdAY”);

//boundary := body_writer.Boundary()



// 1. 要上传的数据
body_writer.WriteField("key1", "value-string1")
body_writer.WriteField("key2", fmt.Sprintf("%d", 45))
// 2. 内存中的文件1,FormFile1
_, err := body_writer.CreateFormFile("filekey1", "filename.txt")
if err != nil {
fmt.Printf("创建FormFile1文件信息异常!", err)
return err
}
f1_content := "内存中文件1的内容";
body_buf.Write([]byte(f1_content))
// 3. 读取文件
_, errr := body_writer.CreateFormFile("filekey2", filename)
if errr != nil {
fmt.Printf("创建FormFile2文件信息异常!", err)
return errr
}
fb2, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Println("打开文件异常!", err)
return err
}
body_buf.Write(fb2)
// 结束整个消息body
body_writer.Close();

//
req_reader := io.MultiReader(body_buf)
req, err := http.NewRequest("POST", url, req_reader)
if err != nil {
fmt.Printf("站点相机上传图片,创建上次请求异常!异常信息:", err)
return err
}
// 添加Post头
req.Header.Set("Connection", "close")
req.Header.Set("Pragma", "no-cache")
req.Header.Set("Content-Type", body_writer.FormDataContentType())
req.ContentLength = int64(body_buf.Len())
fmt.Printf("发送消息长度:", req.ContentLength)
// 发送消息
client := &http.Client{}
resp, err := client.Do(req)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Printf("读取回应消息异常:", err)
}
fmt.Printf("发送回应数据:",string(body))
return nil }


接收上传的文件
unc (this *PostGetController) DoRecePostFormFiel() {
// 读取参数信息
value1 := this.GetString(“key1”)
value2, _ := this.GetInt64(“key2”)
_, fh1, ferr := this.GetFile(“filekey1”)
_, fh2, ferr := this.GetFile(“filekey2”)



// 
fmt.Printf("key1: ", value1)
fmt.Printf("key2: ", value2)

// 保存文件1到目录
fmt.Printf("filekey1-Filename: ", fh1.Filename)
ferr = this.SaveToFile("filekey1", fmt.Sprintf("./%s", fh1.Filename))
if ferr != nil {
fmt.Printf("保存文件1失败:", ferr.Error())
}

// 保存文件2到目录,文件名称前面加file2只是修改保存文件的名称。
fmt.Printf("filekey2-Filename: ", fh2.Filename)
ferr = this.SaveToFile("filekey2", fmt.Sprintf("./file2_%s", fh2.Filename))
if ferr != nil {
fmt.Printf("保存文件2失败:", ferr.Error())
} }



使用curl 上传文件,multipart/form-data





  1. 不使用-F,curl内置multipart/form-data功能;




  2. 文件内容与真实数据无关,用abc代替数据,依然可以上传成功;




  3. name 为服务端获取文件的字段;




  4. 换行和—的数量需要一致。





curl -H “Content-Type: multipart/form-data; boundary=———-0x15f0e7eb752” –data “
————0x15f0e7eb752
Content-Disposition: form-data; name=”file”; filename=”selfi.jpg”
Content-Type: image/png



abc
————0x15f0e7eb752–
“ http://127.0.0.1:1323/upload


Category golang