Heim  >  Artikel  >  Backend-Entwicklung  >  Golang verwendet Multipart, um große Dateien auf eine externe API hochzuladen. So vermeiden Sie das Problem „io.Copy(io.Writer, io.Reader)“.

Golang verwendet Multipart, um große Dateien auf eine externe API hochzuladen. So vermeiden Sie das Problem „io.Copy(io.Writer, io.Reader)“.

PHPz
PHPznach vorne
2024-02-06 09:45:04922Durchsuche

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

Frageninhalt

Mein Ziel ist es, eine große Datei mithilfe des integrierten Net/http-Pakets von Golang auf POST https://somehost/media hochzuladen.

HTTP-Format für API-Aufruf

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--

In Golang ist dies der 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))
}

Wie man io.Copy(io.Writer, io.Reader)Probleme

vermeidet

Der obige Code funktioniert gut, aber in der _, errFile3 = io.Copy(part3, file)-Zeile. Dadurch wird im Wesentlichen alles in der Datei in den Hauptspeicher kopiert.

Wie vermeide ich diese Situation?

Gibt es eine Möglichkeit, große Dateien über multipart-formdata an die API zu streamen?

Das Programm wird auf einem Remote-Server ausgeführt. Kann beim Öffnen einer sehr großen Datei abstürzen.


Richtige Antwort


Verwenden Sie io.Pipe und eine Goroutine, um die Datei in die Anfrage zu kopieren, ohne die gesamte Datei in den Speicher zu laden.

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

Das obige ist der detaillierte Inhalt vonGolang verwendet Multipart, um große Dateien auf eine externe API hochzuladen. So vermeiden Sie das Problem „io.Copy(io.Writer, io.Reader)“.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen

In Verbindung stehende Artikel

Mehr sehen