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(块)的方式进行传输的,从而避免了内存过大的情况