当使用Go发送HTTP请求并接收响应时,考虑到ResponseBody非常大(1 GB或更多),我希望在流式传输的同时接收响应。
resp, err: = http.Client.Do(req)
在这种情况下,如果主体很大,我无法读取标头并且不知道响应的状态。有解决方法吗?
当使用Go发送HTTP请求并接收响应时,考虑到ResponseBody非常大(1 GB或更多),我希望在流式传输的同时接收响应。
resp, err: = http.Client.Do(req)
net/http
包非常好地处理大型响应。以下是一个自包含的示例以进行演示:// Start a mock HTTP server that returns 2GB of data in the response. Make a
// HTTP request to this server and print the amount of data read from the
// response.
package main
import (
"fmt"
"io"
"log"
"net/http"
"strings"
"time"
)
const oneMB = 1024 * 1024
const oneGB = 1024 * oneMB
const responseSize = 2 * oneGB
const serverAddr = "localhost:9999"
func startServer() {
// Mock HTTP server that always returns 2GB of data
go http.ListenAndServe(serverAddr, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-length", fmt.Sprintf("%d", responseSize))
// 1MB buffer that'll be copied multiple times to the response
buf := []byte(strings.Repeat("x", oneMB))
for i := 0; i < responseSize/len(buf); i++ {
if _, err := w.Write(buf); err != nil {
log.Fatal("Failed to write to response. Error: ", err.Error())
}
}
}))
// Some grace period for the server to start
time.Sleep(100 * time.Millisecond)
}
func main() {
startServer()
// HTTP client
req, err := http.NewRequest("GET", "http://"+serverAddr, nil)
if err != nil {
log.Fatal("Error creating HTTP request: ", err.Error())
}
client := http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatal("Error making HTTP request: ", err.Error())
}
// Read the response header
fmt.Println("Response: Content-length:", resp.Header.Get("Content-length"))
bytesRead := 0
buf := make([]byte, oneMB)
// Read the response body
for {
n, err := resp.Body.Read(buf)
bytesRead += n
if err == io.EOF {
break
}
if err != nil {
log.Fatal("Error reading HTTP response: ", err.Error())
}
}
fmt.Println("Response: Read", bytesRead, "bytes")
}
如果响应数据太大,您不希望将其全部存储在内存中。相反,将其写入临时文件,然后再处理。
如果您希望在网络不是很可靠的情况下仍能可靠地完成下载,则可以寻找“HTTP范围请求”选项,使用它可以恢复部分已下载的数据。
resp, err := client.Do(req)
这个过程必须接收到所有响应后才能继续下一个过程,对吗? - hr20k_w.Write(buf)
语句后加上 time.Sleep(5 * time.Second)
然后看看 :) - svsdhttp.Get(...)
,在我的看来,它的行为是相同的。 - Zach Young