Home > Backend Development > Golang > Golang uses multipart to upload large files to external API. How to avoid `io.Copy(io.Writer, io.Reader)` problems

Golang uses multipart to upload large files to external API. How to avoid `io.Copy(io.Writer, io.Reader)` problems

PHPz
Release: 2024-02-06 09:45:04
forward
980 people have browsed it

Golang 使用多部分将大文件上传到外部 API。如何避免`io.Copy(io.Writer, io.Reader)`问题

Question content

My goal is to use golang's built-in net/http package to upload a large file to POST https://somehost /media .

HTTP format for Api call

POST /media HTTP/1.1
Host: somehost
Content-Length: 434
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="detail"

More and more detail
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="some_big_video.mp4"
Content-Type: <Content-Type header here>

(data)
------WebKitFormBoundary7MA4YWxkTrZu0gW--
Copy after login

In golang, this is the code.

package main

import (
  "fmt"
  "bytes"
  "mime/multipart"
  "os"
  "path/filepath"
  "io"
  "net/http"
  "io/ioutil"
)

func main() {

  url := "https://somehost/media"
  method := "POST"

  payload := &bytes.Buffer{}
  writer := multipart.NewWriter(payload)
  _ = writer.WriteField("details", "more and more details")
  file, errFile3 := os.Open("/Users/vajahat/Downloads/some_big_video.mp4")
  defer file.Close()
  part3,errFile3 := writer.CreateFormFile("file","some_big_video.mp4") 
  _, errFile3 = io.Copy(part3, file)
  if errFile3 != nil {
    fmt.Println(errFile3)
    return
  }
  err := writer.Close()
  if err != nil {
    fmt.Println(err)
    return
  }
  client := &http.Client {}
  req, err := http.NewRequest(method, url, payload)

  if err != nil {
    fmt.Println(err)
    return
  }

  req.Header.Set("Content-Type", writer.FormDataContentType())
  res, err := client.Do(req)
  if err != nil {
    fmt.Println(err)
    return
  }
  defer res.Body.Close()

  body, err := ioutil.ReadAll(res.Body)
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(string(body))
}
Copy after login

How to avoidio.Copy(io.Writer, io.Reader)Problems

The above code works fine, but on the line _, errFile3 = io.Copy(part3, file). This essentially copies everything in the file into main memory.

How to avoid this situation?

Is there any way I can stream large files to the api via multipart-formdata?

The program will be run on the remote server. May crash if opening a very large file.


Correct Answer


Use io.Pipe and a goroutine to copy the file to the request without loading the entire file in memory.

pr, pw := io.Pipe()
writer := multipart.NewWriter(pw)
ct := writer.FormDataContentType()
go func() {
    _ = writer.WriteField("details", "more and more details")
    file, err := os.Open("/Users/vajahat/Downloads/some_big_video.mp4")
    if err != nil {
        pw.CloseWithError(err)
        return
    }
    defer file.Close()
    part3, err := writer.CreateFormFile("file", "some_big_video.mp4")
    if err != nil {
        pw.CloseWithError(err)
        return
    }
    _, err = io.Copy(part3, file)
    if err != nil {
        pw.CloseWithError(err)
        return
    }
    pw.CloseWithError(writer.Close())
}()

client := &http.Client{}
req, err := http.NewRequest(method, url, pr)

if err != nil {
    fmt.Println(err)
    return
}

req.Header.Set("Content-Type", ct)
// remaining code as before
Copy after login

The above is the detailed content of Golang uses multipart to upload large files to external API. How to avoid `io.Copy(io.Writer, io.Reader)` problems. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template