Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Golang menggunakan berbilang bahagian untuk memuat naik fail besar ke API luaran. Bagaimana untuk mengelakkan masalah `io.Copy(io.Writer, io.Reader)`

Golang menggunakan berbilang bahagian untuk memuat naik fail besar ke API luaran. Bagaimana untuk mengelakkan masalah `io.Copy(io.Writer, io.Reader)`

PHPz
PHPzke hadapan
2024-02-06 09:45:04923semak imbas

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

Kandungan soalan

Matlamat saya adalah untuk memuat naik fail besar ke POST https://somehost/media menggunakan pakej net/http terbina dalam golang.

Format HTTP untuk panggilan Api

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

Di golang, ini kodnya.

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

Bagaimana untuk mengelakkan io.Copy(io.Writer, io.Reader)masalah

Kod di atas berfungsi dengan baik, tetapi pada baris _, errFile3 = io.Copy(part3, file). Ini pada asasnya menyalin segala-galanya dalam fail ke dalam ingatan utama.

Bagaimana untuk mengelakkan situasi ini?

Adakah ada cara saya boleh menstrim fail besar ke api melalui multipart-formdata?

Program ini akan berjalan pada pelayan jauh. Boleh ranap jika membuka fail yang sangat besar.


Jawapan betul


Gunakan io.Pipe dan goroutine untuk menyalin fail ke permintaan tanpa memuatkan keseluruhan fail dalam memori.

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

Atas ialah kandungan terperinci Golang menggunakan berbilang bahagian untuk memuat naik fail besar ke API luaran. Bagaimana untuk mengelakkan masalah `io.Copy(io.Writer, io.Reader)`. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam

Artikel berkaitan

Lihat lagi