在http.Handler ServeHTTP函数中计算Go中的发送和接收字节数?

时间:2017-05-12 18:29:58

标签: http go

如何在Go中的ServeHTTP函数内计算发送和接收的字节数?

计数需要相对准确。跳过连接建立并不理想,但可以接受。但必须包含标题。

它也需要快速。迭代通常太慢了。

计数本身不需要在ServeHTTP内进行,只要给定连接的计数可以提供给ServeHTTP

这也不能破坏HTTPS或HTTP / 2.

我尝试过的事情

通过迭代Request标头,可以对接收到的字节进行粗略,缓慢的估计。这太慢了,Go标准库删除并组合了标题,所以它也不准确。

我尝试编写一个拦截Listener,它创建了一个内部tls.Listennet.Listen侦听器,其Accept()函数从内部侦听器获得net.Conn Accept(),然后将其包含在拦截net.Conn中,其ReadWrite函数调用真实net.Conn并计算其读写次数。然后可以通过互斥共享变量将这些计数提供给ServeHTTP函数。

问题是,拦截Conn打破了HTTP / 2,因为Go的内部库将net.Conn强制转换为*tls.Conn(例如https://golang.org/src/net/http/server.go#L1730),并且它没有似乎可以在Go中包裹对象,同时仍然使该转换成功(如果是,它将解决此问题)。

通过计算写入ResponseWriter的内容,可以相对准确地计算发送的字节数。通过Request.Body计算HTTP主体中接收的字节数也是可以实现的。这里的关键问题似乎是快速准确地计算请求头字节。尽管如此,计算连接建立字节也是理想的。

这可能吗?怎么样?

1 个答案:

答案 0 :(得分:2)

我认为这是可能的,但我不能说我已经做到了。但是,基于浏览HTTP服务器和TLS监听器的stdlib实现,我不明白为什么它不可能;关键是在 TLS之前包装连接而不是之后的。这也可以在线上获得更精确的字节数,而不是解密字节数。

您已经有拦截Listener,您只需将其插入正确的位置即可。而不是将Listener传递给http.Serve(或者您将其插入的任何地方),您希望首先将其传递给tls.NewListener,然后将其包装在TLS处理程序中,然后传递结果,这将是一个TLS监听器(使Go的HTTP / 2支持很高兴)进入HTTP服务器。

当然,如果你想要一个解密字节而不是有线字节的数量,你可能是SOL - 包裹net.Conn只是赢了,不能让你到那里。您可能需要尽可能地利用计数标题和&体。