有很多关于使用http.Requestgo 发布文件的教程,但是几乎总是以这样的方式开始:
http.Request
file, err := os.Open(path) if err != nil { return nil, err } fileContents, err := ioutil.ReadAll(file)
也就是说,您将整个文件读入内存,然后将其转换为Buffer并将其传递给请求,如下所示:
Buffer
func send(client *http.Client, file *os.File, endpoint string) { body := &bytes.Buffer{} io.Copy(body, file) req, _ := http.NewRequest("POST", endpoint, body) resp, _ := client.Do(req) }
如果您想发布海量文件并避免将其读取到内存中,而是将文件分块蒸出……您将如何做?
如果需要设置Content-Length,可以手动完成。以下代码段是将文件和其他参数作为流上传的示例(基于Golang中无缓冲区Multipart POST的代码)
Content-Length
//NOTE: for simplicity, error check is omitted func uploadLargeFile(uri, filePath string, chunkSize int, params map[string]string) { //open file and retrieve info file, _ := os.Open(filePath) fi, _ := file.Stat() defer file.Close() //buffer for storing multipart data byteBuf := &bytes.Buffer{} //part: parameters mpWriter := multipart.NewWriter(byteBuf) for key, value := range params { _ = mpWriter.WriteField(key, value) } //part: file mpWriter.CreateFormFile("file", fi.Name()) contentType := mpWriter.FormDataContentType() nmulti := byteBuf.Len() multi := make([]byte, nmulti) _, _ = byteBuf.Read(multi) //part: latest boundary //when multipart closed, latest boundary is added mpWriter.Close() nboundary := byteBuf.Len() lastBoundary := make([]byte, nboundary) _, _ = byteBuf.Read(lastBoundary) //calculate content length totalSize := int64(nmulti) + fi.Size() + int64(nboundary) log.Printf("Content length = %v byte(s)\n", totalSize) //use pipe to pass request rd, wr := io.Pipe() defer rd.Close() go func() { defer wr.Close() //write multipart _, _ = wr.Write(multi) //write file buf := make([]byte, chunkSize) for { n, err := file.Read(buf) if err != nil { break } _, _ = wr.Write(buf[:n]) } //write boundary _, _ = wr.Write(lastBoundary) }() //construct request with rd req, _ := http.NewRequest("POST", uri, rd) req.Header.Set("Content-Type", contentType) req.ContentLength = totalSize //process request client := &http.Client{} resp, err := client.Do(req) if err != nil { log.Fatal(err) } else { log.Println(resp.StatusCode) log.Println(resp.Header) body := &bytes.Buffer{} _, _ = body.ReadFrom(resp.Body) resp.Body.Close() log.Println(body) } }