首页 文章

扩展Golang的http.Resp.Body来处理大文件

提问于
浏览
1

我有一个客户端应用程序,它将http响应的完整主体读入缓冲区并对其执行一些处理:

body,_ = ioutil.ReadAll(containerObject.Resp.Body)

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

为避免这种情况,我检查内容长度 Headers 并在文档太大时绕过处理 . 但是,有些服务器(我在看你,微软)发送非常大的html响应而没有设置内容长度并使设备崩溃 .

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

我是GoLang的新手,我不知道如何编写这个 . 任何建议或替代解决方案将不胜感激 .

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

编辑2:我无法解析文档的小块 . 处理整个文档或将其未更改地传递给调用者,而不将其加载到内存中 .

1 回答

  • 2

    如果您需要阅读部分响应主体,然后为其他呼叫者重新构建它,您可以使用io.MultiReaderioutil.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),
    }
    

相关问题