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