【问题标题】:Read request body without draining it using json.decoder [duplicate]读取请求正文而不使用 json.decoder [重复]
【发布时间】:2021-08-09 20:40:05
【问题描述】:

我有一个应用程序正在读取大量请求(大约 4-5 百万个请求/秒)

我正在使用 json.decoder 从请求正文中读取传入的 json 数据。

我的代码:

err := json.NewDecoder(c.Request.Body).Decode(&obj)

上面的代码 sn -p 耗尽了请求体。有什么办法可以将其流式传输回来,以便在代码中再次读取它?

例如,在使用 io util 库时,我可以这样做:

c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

我正在寻找的解决方案类似于:

err := json.NewDecoder(c.Request.Body).Decode(&obj)
if err != nil {
    return err
}
b := new(bytes.Buffer)
c.Request.Body = json.NewEncoder(b).Encode(obj)

但显然不支持c.Request.Body = json.NewEncoder(b).Encode(obj)

我不能使用 ioutil 库,因为它很难管理冗长的请求。

【问题讨论】:

  • 读取阅读器而不耗尽阅读器的唯一方法是缓冲其内容(通常在内存中或磁盘上)。
  • 不过,您并没有真正很好地解释您的问题。您所说的您尝试过的三个“解决方案”没有明显的共同点。目前尚不清楚其中任何一个,更不用说所有这些,如何解决您的问题。你能更清楚地解释你的问题吗?
  • 再次编组和编组总是比读入缓冲区慢,并设置一个读取器来生成缓冲区的内容。所以就这样做吧。见Golang read request body multiple times
  • however I see the response time increasing over time 这在我心中敲响了关于 GC 的警钟。我想建议使用sync.Poolio.CopyBuffer 减少您的分配。但我也同意 Flimzy 的评论,你的帖子不够清晰。
  • @Flimzy 请检查一下,我已经简化了问题陈述

标签: go io go-gin


【解决方案1】:

如果您的唯一目标是重新填充请求正文,那么您已经展示了如何做到这一点:

c.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))

如果您想从 json 编码器的结果中执行此操作,同样简单:

bodyBytes, err := json.Marshal(obj)
if err != nil { /* error handling */ }
c.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyBytes))

但是,正如 cmets 中所述,这将比缓冲请求正文的效率低很多倍,正如您似乎已经在做的那样。

【讨论】:

    【解决方案2】:

    io.TeeReader的例子

    package main
    
    import (
        "io"
        "os"
        "strings"
    )
    
    func main() {
        var r io.Reader = strings.NewReader("some io.Reader stream to be read\n")
    
        r = io.TeeReader(r, os.Stdout)
    
        // Everything read from r will be copied to stdout.
        io.ReadAll(r)
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-31
      • 2013-09-06
      相关资源
      最近更新 更多