golang使用post方法传输大文件,占内存最小的方式
通常想要用post方法发送什么文件的时候可以用这样的一种简单方式:
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", params["file"])
if err != nil {
return err
}
src, err := os.Open(filename)
if err != nil {
return err
}
defer src.Close()
_, err = io.Copy(part, src)
if err != nil {
return err
}
for key, val := range params {
writer.WriteField(key, val)
}
err = writer.Close()
if err != nil {
return err
}
request, err := http.NewRequest("POST", uri, body)
if err != nil {
return err
}
request.Header.Add("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
return err
}
defer resp.Body.Close()
这样做很方便的就能发送一个文件了。
不过以这样的方式可以很明显的发现,如果读取的文件很大的话,用来接收的body字段会很大很占内存。
HTTP/1.1 有一种无限制地以块的形式传输数据的方法,无需指定Content-Length请求主体,这是我们可以利用的一个重要特性。
我们可以使用io.Pipe
r, w := io.Pipe()
m := multipart.NewWriter(w)
go func() {
defer w.Close()
defer m.Close()
part,err := m.CreateFormFile("myFile", "foo.txt")
if err != nil {
return
}
file, err := os.Open(name)
if err != nil {
return
}
defer file.Close()
if _, err = io.Copy(part, file); err!=nil{
return
}
}()
http.Post(url, m.FormDataContentType(), r)
这样的传输方式,在接收方解析header的时候会发现它是以block(块)的方式进行传输的,从而避免了内存过大的情况