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



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

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

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

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

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

我尝试过的事情

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

我尝试编写一个拦截Listener,它创建了一个内部tls.Listennet.Listen监听器,其Accept()函数从内部监听器的Accept()中获取net.Conn,然后将其包装在一个拦截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 正文中计算接收的字节数。这里的关键问题似乎是快速准确地计算请求标头字节数。虽然同样,计算连接建立字节也是理想的。

这可能吗?如何?

我认为这是可能的,但我不能说我已经做到了。但是,基于浏览HTTP服务器和TLS侦听器的stdlib实现,我不明白为什么它不应该是不可能的;密钥是在 TLS之前而不是之后包装连接。这还可以为您提供更准确的线路字节计数,而不是解密字节计数。

你已经有一个拦截Listener,你只需要把它插入正确的位置。与其将Listener传递给http.Serve(或插入它的任何位置),不如先将其传递给tls.NewListener,后者将其包装在TLS处理程序中,然后将结果(该结果将是一个TLS侦听器(使Go的HTTP/2支持满意)传递到HTTP服务器。

当然,如果你想要一个解密字节数而不是有线字节,你可能就是 SOL - 包装net.Conn不会让你到达那里。你可能必须尽你所能来计算标题和正文。

最新更新