我的目标是使用 golang 的内置 net/http 包将一个大文件上传到 POST https://somehost/media
。
Api调用的HTTP格式
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:
(data)
------WebKitFormBoundary7MA4YWxkTrZu0gW--
在 golang 中,这是代码。
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))
}
如何避免io.Copy(io.Writer, io.Reader)
问题
上面的代码工作正常,但是在 _, 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)`问题的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756