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

golang 使用多部分将大文件上传到外部 api。如何避免`io.copy(io.writer, io.reader)`问题

问题内容

我的目标是使用 golang 的内置 net/http 包将一个大文件上传到 POST https://somehost/media 。

Api调用的HTTP格式

POST /media HTTP/1.1Host: somehostContent-Length: 434Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="detail"More and more detail------WebKitFormBoundary7MA4YWxkTrZu0gWContent-Disposition: form-data; name="file"; filename="some_big_video.mp4"Content-Type: (data)------WebKitFormBoundary7MA4YWxkTrZu0gW--

登录后复制

在 golang 中,这是代码。

package mainimport (  "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))}

登录后复制

如何避免io.Copy(io.Writer, io.Reader)问题

立即学习“go语言免费学习笔记(深入)”;

上面的代码工作正常,但是在 _, errFile3 = io.Copy(part3, file) 行上。这实际上将文件中的所有内容复制到主内存中。

如何避免这种情况?

有什么办法,我可以通过 multipart-formdata 将大文件流式传输到 api?

该程序将在远程服务器上运行。如果打开一个非常大的文件,可能会崩溃。

正确答案

使用 io.Pipe 和 goroutine 将文件复制到请求而不加载整个文件内存中的文件。

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

登录后复制

以上就是Golang 使用多部分将大文件上传到外部 API。如何避免`io.Copy(io.Writer, io.Reader)`问题的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2485456.html

(0)
上一篇 2025年3月4日 21:46:46
下一篇 2025年3月4日 21:47:05

AD推荐 黄金广告位招租... 更多推荐

相关推荐

发表回复

登录后才能评论