我可以在发布前获取http.NewRequest的大小吗?

时间:2019-07-12 10:02:03

标签: json go httprequest gzip

我们有一个接受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请求的大小?如果没有,我应该可以使用MyJSON []byte来获得原始len()的大小,但是对于压缩版本,我似乎无法得到bytes.Buffer的大小。 / p>

2 个答案:

答案 0 :(得分: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)直接“完成”到网络,而无需使用内存的中间缓冲区,从而推迟了您的请求。

答案 1 :(得分:0)

问题询问如何获取请求主体的长度,其中主体是字节片或byte.Buffer。

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

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