【问题标题】:Can I get the size of a http.NewRequest before I POST?我可以在发布之前获得 http.NewRequest 的大小吗?
【发布时间】:2019-07-12 10:02:03
【问题描述】:

我们有一个接受 JSON 的 API。我们鼓励人们在发布之前对有效负载进行 gzip,因为我们对大小施加了限制。我想查看原始 JSON 和 gzip 之间的实际大小差异,但我似乎无法可靠准确地获取构建后的 http 请求的大小。

对于非压缩版本,MyJSON []byte 是我将其填充到 http 请求之前的原始数据,如下所示:

req, err := http.NewRequest("POST", url, bytes.NewBuffer(MyJSON))

对于 gzip 版本,我将数据压缩到缓冲区中,然后将其添加到 http 请求中,如下所示:

req, err := http.NewRequest("POST", url, &buffer)

是否可以获取http请求的大小?如果没有,我应该能够使用len() 获得原始MyJSON []byte 的大小,但我似乎无法获得压缩版本的bytes.Buffer 的大小。

【问题讨论】:

标签: json go httprequest gzip


【解决方案1】:

一句话:没有。

这是因为http.Request 对象的主体是io.Reader,它可以有任何大小,而知道io.Reader 大小的唯一方法是全部阅读并计数。而在实践中,io.Reader 甚至在数据已经开始传输之后才会被使用。

这对您的应用程序意味着您有两种选择:

  1. 您可以先读取整个正文,然后将其缓冲(在内存中或磁盘上),计算其大小,然后发送。
  2. 通过网络发送请求后,您可以找到一种计算(或估计)大小的方法。

后者效率更高,但意味着您无法在发送请求之前主动对数据采取行动。如果您选择第二种方法,您可以编写一个自定义 io.Reader 来计算读取的字节数,并将其传递给您的 NewRequest() 调用。


另请注意:将 JSON 保存在字节切片 ([]byte) 中的事实有点代码味道。这在某些情况下可能是合适的,但在大多数情况下,将 JSON 直接流式传输到 HTTP 请求会更有效(就内存和时间而言)。示例:

var someBigHairyObject = /* Perhaps a struct or map */
r, w := io.Pipe()
go func() {
    err := json.NewEncoder(w).Encode(someBigHairyObject)
    w.CloseWithError(err)
}()
req, _ := http.NewRequest("POST", "http://example.com/", r)

通过这种方式,JSON 封送处理(您也可以在此处包含 gzip)“直接”在网络中完成,无需使用内存并推迟您的请求的中间缓冲区。

【讨论】:

  • 对于它的价值,如果文档非常大,我只对 HTTP 请求使用编码器。否则 json.Marshal 更简单,并允许在开始请求之前处理编码错误。
  • @Flimzy 我认为你的 w 和 r 颠倒了 :)
【解决方案2】:

问题询问如何获取请求正文的长度,其中正文是字节切片或 bytes.Buffer。

如问题中所述,使用内置的len 函数来获取字节片的长度。

使用Buffer.Len 获取缓冲区内容的长度。

【讨论】:

    猜你喜欢
    • 2011-10-31
    • 2018-08-10
    • 1970-01-01
    • 2012-02-26
    • 2014-09-11
    • 2020-03-17
    • 1970-01-01
    • 2012-08-14
    • 1970-01-01
    相关资源
    最近更新 更多