读取http.Response的Body流。

5
我正在发送一个HTTP请求并以text/xml格式获取响应。我不需要解析XML,只是想将其作为字符串返回以进行测试。但它似乎非常缓慢。
XML响应的大小为278kb,但读取响应正文可能需要约1.7秒,有时会突然增加到4.5秒。我可以一遍又一遍地重新运行它,结果会有很大变化。由于我刚开始使用Go,所以我不确定是什么原因导致了这个问题。
我觉得ioutil.ReadAll()函数让我失望了。但我也尝试过bufio.NewReader和reader.ReadBytes。所有这些都一样慢。
以下是我的函数内容:
client := &http.Client{}
req, err := http.NewRequest("POST", url, strings.NewReader(requestBody))
if err != nil {
    fmt.Println("New Request Error", err)
}

// Set Headers
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Content-Encoding", "gzip")
req.Header.Set("Accept-Encoding", "gzip, deflate")

defer req.Body.Close()

// Get Response
startRes := time.Now()
response, err := client.Do(req)
if response != nil {
    defer response.Body.Close()
}
if err != nil {
    fmt.Println("POST Error", err)
}
endRes := time.Now()
fmt.Println("Response took", endRes.Sub(startRes))

// Read Response Body
startRead := time.Now()
body, readErr := ioutil.ReadAll(response.Body)
if readErr != nil {
    fmt.Println("body error:", readErr)
    return nil, readErr
}

endRead := time.Now()
fmt.Println("Read response took:", endRead.Sub(startRead))

这些println的输出看起来像这样:

> go run main.go
 Response took 5.230523s
 Read response took: 1.7551755s

有没有办法让这段代码更高效?我猜278kb文件的1.7秒读取时间是由网络延迟引起的,对吗?

1
我认为这是网络或服务器问题。为什么不使用其他工具进行测试,比如JMeter呢? - Jiang YD
1个回答

7
我建议分配一个byte.Buffer并自己读取正文。在代码ioutil.ReadAll中,创建了一个初始容量为Byte.MinRead(512字节)的byte.Buffer

当Buffer达到278KB时,需要扩展、重新分配和重新复制返回的字节数组10次,这是大部分处理时间所花费的(对于您可以控制的事情)。

以下是未经测试的代码:

buf := bytes.NewBuffer(make([]byte, 0, response.ContentLength))
_, readErr = buf.ReadFrom(response.Body)
body := buf.Bytes()

1
没有任何改变。仍然需要约1.7秒的时间。我开始认为这纯粹是由于网络延迟造成的。我尝试在与服务器相同的局域网上运行此程序,它只需要大约21-25毫秒就能读取。 - mnsr
真遗憾:( - 对于一个微小的负载(~1.2 Mb/s)来说,那是相当长的时间。 - Kevin Deenanauth
4
值得注意的是response.ContentLength有可能返回-1,这会导致在创建缓冲区时出现运行时错误“makeslice: cap out of range”。 - PassKit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接