我有一个客户端应用程序,它将HTTP响应的整个内容读入缓冲区并对其进行一些处理:

正文,_ = ioutil.ReadAll(containerObject.Resp.Body)

问题在于该应用程序在嵌入式设备上运行,因此太大的响应会填满设备RAM,从而导致Ubuntu终止进程。

为避免这种情况,如果文档太大,我将检查content-length标题并绕过处理。但是,某些服务器(我正在向您询问,Microsoft)会发送非常大的html响应,而没有设置content-length并使设备崩溃。

我能看到的解决此问题的唯一方法是读取响应正文达一定长度。如果达到此限制,则可以创建一个新的读取器,该读取器首先对内存缓冲区进行流处理,然后继续从原始的Resp.Body中读取数据。理想情况下,我会将这个新的阅读器分配给containerObject.Resp.Body,以便调用者不知道它们之间的区别。

我是GoLang的新手,不确定如何编写代码。任何建议或替代解决方案将不胜感激。

编辑1:调用方需要一个Resp.Body对象,因此解决方案需要与该接口(interface)兼容。

编辑2:我无法解析文档的小块。要么处理整个文档,要么将其原封不动地传递给调用者,而无需将其加载到内存中。

最佳答案

如果需要阅读响应主体的一部分,然后将其重构为其他调用者使用,则可以结合使用 io.MultiReader ioutil.NopCloser

resp, err := http.Get("http://google.com")
if err != nil {
    return err
}
defer resp.Body.Close()

part, err := ioutil.ReadAll(io.LimitReader(resp.Body, maxReadSize))
if err != nil {
    return err
}

// do something with part

// recombine the buffered part of the body with the rest of the stream
resp.Body = ioutil.NopCloser(io.MultiReader(bytes.NewReader(part), resp.Body))

// do something with the full Response.Body as an io.Reader

如果您无法defer resp.Body.Close(),因为您打算在完整读取响应之前返回该响应,则需要扩展替换正文,以便Close()方法适用于原始正文。与其使用ioutil.NopCloser作为io.ReadCloser,不如创建自己的引用正确的方法调用。
type readCloser struct {
    io.Closer
    io.Reader
}

resp.Body = readCloser{
    Closer: resp.Body,
    Reader: io.MultiReader(bytes.NewReader(part), resp.Body),
}

关于go - 扩展Golang的http.Resp.Body以处理大文件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46224373/

10-11 10:39