通过 http POST 发送 os.Stdin 而不将文件加载到内存中
Send os.Stdin via http POST without loading file into memory
我正在尝试通过 POST 请求将文件发送到服务器。为此,我使用以下代码:
func newfileUploadRequest(uri string) (*http.Request, error) {
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", "file")
if err != nil {
return nil, err
}
io.Copy(part, os.Stdin)
err = writer.Close()
if err != nil {
return nil, err
}
request, err := http.NewRequest("POST", uri, body)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", writer.FormDataContentType())
return request, nil
}
func main() {
r, err := newfileUploadRequest("http://localhost:8080/")
if err != nil {
panic(err)
}
client := &http.Client{}
resp, err := client.Do(r)
if err != nil {
panic(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
print(string(body))
}
虽然这很有效,但我的理解是 io.Copy 会在发送 POST 请求之前将整个文件复制到内存中。大文件(多个 GB)会产生问题。有没有办法防止这种情况?我找到了 this,但这只是说要使用 io.Copy。
使用io.Pipe()
- https://golang.org/pkg/io/#Pipe
您将需要使用 goroutine,但这并不难做到。如果您需要一个具体的示例,请发表评论,我会为您准备一个。
您可以通过使用 io.Pipe 和从文件复制到管道的 goroutine 来避免复制内存中的数据:
func newfileUploadRequest(uri string) (*http.Request, error) {
r, w := io.Pipe()
writer := multipart.NewWriter(w)
go func() {
part, err := writer.CreateFormFile("file", "file")
if err != nil {
w.CloseWithError(err)
return
}
_, err = io.Copy(part, os.Stdin)
if err != nil {
w.CloseWithError(err)
return
}
err = writer.Close()
if err != nil {
w.CloseWithError(err)
return
}
}()
request, err := http.NewRequest("POST", uri, r)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", writer.FormDataContentType())
return request, nil
}
我正在尝试通过 POST 请求将文件发送到服务器。为此,我使用以下代码:
func newfileUploadRequest(uri string) (*http.Request, error) {
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", "file")
if err != nil {
return nil, err
}
io.Copy(part, os.Stdin)
err = writer.Close()
if err != nil {
return nil, err
}
request, err := http.NewRequest("POST", uri, body)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", writer.FormDataContentType())
return request, nil
}
func main() {
r, err := newfileUploadRequest("http://localhost:8080/")
if err != nil {
panic(err)
}
client := &http.Client{}
resp, err := client.Do(r)
if err != nil {
panic(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
print(string(body))
}
虽然这很有效,但我的理解是 io.Copy 会在发送 POST 请求之前将整个文件复制到内存中。大文件(多个 GB)会产生问题。有没有办法防止这种情况?我找到了 this,但这只是说要使用 io.Copy。
使用io.Pipe()
- https://golang.org/pkg/io/#Pipe
您将需要使用 goroutine,但这并不难做到。如果您需要一个具体的示例,请发表评论,我会为您准备一个。
您可以通过使用 io.Pipe 和从文件复制到管道的 goroutine 来避免复制内存中的数据:
func newfileUploadRequest(uri string) (*http.Request, error) {
r, w := io.Pipe()
writer := multipart.NewWriter(w)
go func() {
part, err := writer.CreateFormFile("file", "file")
if err != nil {
w.CloseWithError(err)
return
}
_, err = io.Copy(part, os.Stdin)
if err != nil {
w.CloseWithError(err)
return
}
err = writer.Close()
if err != nil {
w.CloseWithError(err)
return
}
}()
request, err := http.NewRequest("POST", uri, r)
if err != nil {
return nil, err
}
request.Header.Set("Content-Type", writer.FormDataContentType())
return request, nil
}