问题内容
我的目标是使用 golang 的内置 net/http 包将一个大文件上传到
。
Api调用的HTTP格式
在 golang 中,这是代码。
如何避免问题
立即学习
“
go语言免费学习笔记(深入)
”;
上面的代码工作正常,但是在
行上。这实际上将文件中的所有内容复制到主内存中。
微信接口库:PHPToQyWeixin PHP调用企业微信API接口底层类库
下载
如何避免这种情况?
有什么办法,我可以通过
将大文件流式传输到 api?
该程序将在远程服务器上运行。如果打开一个非常大的文件,可能会崩溃。
正确答案
使用
io.Pipe
和 goroutine 将文件复制到请求而不加载整个文件内存中的文件。
POST https://somehost/mediaPOST /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--
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-formdatapr, 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