Golang :如何在块中读取和处理请求正文,并在请求正文中再次将其设置回去,而无需将其作为一个整体加载到内存中?[已结束]

Golang : How to read and process request body in chunks and set it back again in request body without loading it as a whole in memory? [closed]

提问人:Subhankar 提问时间:5/5/2023 最后编辑:Subhankar 更新时间:5/5/2023 访问量:781

问:


这个问题是由一个错别字或一个无法再重现的问题引起的。虽然类似的问题可能在这里成为主题,但这个问题的解决方式不太可能帮助未来的读者。

7个月前关闭。

我们有一个 go Web 服务器,我们尝试在其中读取块中的请求正文内容以处理某些内容。但是,必须在工作完成后转发请求,因此必须再次重置请求正文。由于在不重置它的情况下无法从 request.body 中多次读取它,因此我们使用的是 Wrapper Reader 对象,该对象以块形式读取并将其并行写入缓冲区。在处理结束时,我们再次将此缓冲区添加到请求正文中。但是,由于缓冲区最终会加载整个内容,因此如果内容非常大,这将是一个问题。

package main

import (
    "bytes"
    "encoding/json"
    "errors"
    "fmt"
    "io"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/", handleRequest)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func handleRequest(w http.ResponseWriter, req *http.Request) {
    maxSize := int64(1000000)
    b := bytes.Buffer{}
    b.Write(make([]byte, 0, maxSize))

    reader := MyReader{
        r:       req.Body,
        buf:     b,
        size:    0,
        maxSize: maxSize,
    }

    err := Validate(&reader)
    if err != nil {
        panic(err)
    }
    r := reader.GetBuffer()
    fmt.Println(len(r.Bytes()))
    req.Body = io.NopCloser(&r)

    //pass the body back for the next handler!
}

type MyReader struct {
    r       io.Reader
    buf     bytes.Buffer
    size    int64
    maxSize int64
}

func (rd *MyReader) Read(p []byte) (n int, err error) {
    n, err = rd.r.Read(p)
    if n > 0 {
        rd.size = rd.size + int64(n)
        if n, err := rd.buf.Write(p[:n]); err != nil {
            return n, err
        }
    }
    return n, err
}

func (rd *MyReader) GetBuffer() bytes.Buffer {
    return rd.buf
}

func Validate(reader *MyReader) error {
    //Get standard json decoder
    decoder := json.NewDecoder(reader)

    for {
        //decode next token
        t, err := decoder.Token()
        //Validate the token - should not throw any error
        if err == io.EOF {
            return nil
        }

        if err != nil {
            return errors.New("Some error")
        }
        fmt.Println(t)
        //processing being done on the token
    }

}

有没有办法避免缓冲区并将内容流式传输回请求正文,而无需在内存中读取它?

Go IO 缓冲区

评论

0赞 Volker 5/5/2023
你可以直接流式传输你芦苇的内容,使用 io。TeeReader,你似乎知道。只是不要缓冲,而是直接向下游发送。
1赞 Subhankar 5/5/2023
@Volker 问题在于 TeeReader 需要一个 writer 对象。但在本例中,我们希望将其重置为请求正文本身,以便下一个处理单元可以再次从正文中读取。
2赞 Volker 5/5/2023
啊。我理解。你根本无法做到这一点。这不是时间在这个宇宙中的运作方式。你要么必须流式传输要么必须缓冲。
2赞 JimB 5/5/2023
您所描述的是,您想流式传输响应,然后再次“流式传输”它,而无需将其存储在任何地方?执行此操作的唯一合乎逻辑的方法是按照建议同时处理流,并使用管道将编写器连接到另一个读取器,但您当前串行处理数据并“将正文传回给下一个处理程序”的设计是不可能的。io.TeeReader
1赞 Jishan Shaikh 5/5/2023
您想将内容流式传输回请求正文,而不在内存中缓冲它吗?同时将其写入两个不同的目标。一个目标是您的处理逻辑,另一个目标是原始请求正文。

答: 暂无答案