如何在Go中的ServeHTTP
函数内计算发送和接收的字节数?
计数需要相对准确。跳过连接建立并不理想,但可以接受。但必须包含标题。
它也需要快速。迭代通常太慢了。
计数本身不需要在ServeHTTP
内进行,只要给定连接的计数可以提供给ServeHTTP
。
这也不能破坏HTTPS或HTTP / 2.
我尝试过的事情
通过迭代Request
标头,可以对接收到的字节进行粗略,缓慢的估计。这太慢了,Go标准库删除并组合了标题,所以它也不准确。
我尝试编写一个拦截Listener
,它创建了一个内部tls.Listen
或net.Listen
侦听器,其Accept()
函数从内部侦听器获得net.Conn
Accept()
,然后将其包含在拦截net.Conn
中,其Read
和Write
函数调用真实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主体中接收的字节数也是可以实现的。这里的关键问题似乎是快速准确地计算请求头字节。尽管如此,计算连接建立字节也是理想的。
这可能吗?怎么样?
答案 0 :(得分:2)
我认为这是可能的,但我不能说我已经做到了。但是,基于浏览HTTP服务器和TLS监听器的stdlib实现,我不明白为什么它不可能;关键是在 TLS之前包装连接而不是之后的。这也可以在线上获得更精确的字节数,而不是解密字节数。
您已经有拦截Listener
,您只需将其插入正确的位置即可。而不是将Listener
传递给http.Serve
(或者您将其插入的任何地方),您希望首先将其传递给tls.NewListener
,然后将其包装在TLS处理程序中,然后传递结果,这将是一个TLS监听器(使Go的HTTP / 2支持很高兴)进入HTTP服务器。
当然,如果你想要一个解密字节而不是有线字节的数量,你可能是SOL - 包裹net.Conn
只是赢了,不能让你到那里。您可能需要尽可能地利用计数标题和&体。