Go 延长戈朗';s http.Resp.Body来处理大型文件

Go 延长戈朗';s http.Resp.Body来处理大型文件,go,Go,我有一个客户端应用程序,它将http响应的全部内容读入缓冲区并对其执行一些处理: body,uUtil=ioutil.ReadAll(containerObject.Resp.body) 问题是这个应用程序运行在嵌入式设备上,所以太大的响应会填满设备RAM,导致Ubuntu终止进程 为了避免这种情况,我检查内容长度标题,如果文档太大,则跳过处理。但是,有些服务器(我在看你,微软)在不设置内容长度的情况下发送非常大的html响应,导致设备崩溃 我能看到的唯一绕过这个问题的方法是将响应体读到一定的长

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

body,uUtil=ioutil.ReadAll(containerObject.Resp.body)

问题是这个应用程序运行在嵌入式设备上,所以太大的响应会填满设备RAM,导致Ubuntu终止进程

为了避免这种情况,我检查内容长度标题,如果文档太大,则跳过处理。但是,有些服务器(我在看你,微软)在不设置内容长度的情况下发送非常大的html响应,导致设备崩溃

我能看到的唯一绕过这个问题的方法是将响应体读到一定的长度。如果达到此限制,则可以创建一个新的读取器,该读取器首先对内存缓冲区进行流式处理,然后继续从原始Resp.Body读取。理想情况下,我会将这个新读取器分配给containerObject.Resp.Body,这样调用方就不会知道其中的区别

我是刚来GoLang的新手,不知道如何编写代码。如有任何建议或替代方案,将不胜感激

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


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

如果需要读取响应正文的一部分,然后为其他调用者重新构建它,则可以使用和的组合

如果您无法
延迟resp.Body.Close()
,因为您打算在完整读取响应之前返回响应,则需要增加替换体,以便
Close()
方法应用于原始体。不要将
ioutil.nocloser
用作
io.ReadCloser
,而是创建自己的引用正确方法调用的方法

type readCloser struct {
    io.Closer
    io.Reader
}

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

不设置
内容长度
是相当标准的,因为大多数大型响应都将使用分块编码。为什么要尝试有条件地缓冲响应的一部分,而不仅仅是在整个过程中使用
io.Reader
接口?为了进一步@JimB推荐,我将开始考虑以下内容:这可能也很有用:一旦您从Resp.Body读取任何内容,您必须将其缓冲在内存中(如果您想对其执行任何操作,也就是说),因为您正在从网络流读取。这意味着一个大的响应被完全读取到内存中,并导致设备崩溃。另一方面,这个函数的调用者希望Resp.Body保持完整,就像它是直接从http对象读取的一样。所以我需要发送一个类似于那个对象的东西,但不要试图将大文档完全读入RAM。谢谢你的建议,克里斯蒂安。不幸的是,我不能一次处理小批量的文档。这是一件要么全有要么全无的事情。如果我看不到整个文档,那么我想原封不动地传递它。我将编辑问题以反映这一点。这看起来正是我所需要的。我会实施并很快回复你。关于这一点,有一个问题。如果用新对象替换resp.Body,则“defer resp.Body.Close()”将关闭新对象,同时保持原始主体打开,从而导致内存泄漏。你知道这会不会有同样的问题吗?或者将在原始响应主体上调用Close?此处的
延迟响应主体关闭()
将在原始
响应主体上求值;以后更换不会影响它。唯一需要注意的是,您不能将
resp
返回到任何消耗主体的对象,因为主体将在该点关闭。我仍然不明白,如果打电话的人要再读一遍,先读正文有什么好处。您也不会阻止下一个调用方读取太多内容并耗尽内存。为什么不首先限制响应大小?奇怪的是,替换resp.Body.Close并没有像预期的那样关闭原始resp.Body。不知道为什么,但在Golang论坛上有一篇关于这一点的帖子,我可以用我自己的代码确认这一点(在重新分配之前关闭了原始响应机构后,代码不再显示泄漏)。至于你的评论的后半部分,设备本身处理http响应,然后通过网络将其传递给客户机,客户机将其直接写入磁盘。我很确定,这种情况主要发生在微软传输二进制更新并将其标记为html页面时。
type readCloser struct {
    io.Closer
    io.Reader
}

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