Go 博客
介绍 HTTP 追踪
介绍
在 Go 1.7 中,我们引入了 HTTP 追踪,这是一种在 HTTP 客户端请求的生命周期中收集细粒度信息的工具。HTTP 追踪支持由 net/http/httptrace
包提供。收集到的信息可用于调试延迟问题、服务监控、编写自适应系统等。
HTTP 事件
httptrace
包提供了一些钩子,用于在 HTTP 往返过程中收集有关各种事件的信息。这些事件包括
- 连接创建
- 连接重用
- DNS 查询
- 将请求写入网络
- 读取响应
追踪事件
您可以通过将包含钩子函数的 *httptrace.ClientTrace
放入请求的 context.Context
中来启用 HTTP 追踪。各种 http.RoundTripper
实现通过查找上下文中的 *httptrace.ClientTrace
并调用相关的钩子函数来报告内部事件。
追踪范围限定在请求的上下文中,用户应在开始请求之前将 *httptrace.ClientTrace
放入请求上下文。
req, _ := http.NewRequest("GET", "http://example.com", nil) trace := &httptrace.ClientTrace{ DNSDone: func(dnsInfo httptrace.DNSDoneInfo) { fmt.Printf("DNS Info: %+v\n", dnsInfo) }, GotConn: func(connInfo httptrace.GotConnInfo) { fmt.Printf("Got Conn: %+v\n", connInfo) }, } req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) if _, err := http.DefaultTransport.RoundTrip(req); err != nil { log.Fatal(err) }
在往返过程中,http.DefaultTransport
将在发生事件时调用每个钩子。上面的程序将在 DNS 查询完成后立即打印 DNS 信息。它还会在与请求主机建立连接时类似地打印连接信息。
使用 http.Client 进行追踪
追踪机制旨在追踪单个 http.Transport.RoundTrip
生命周期中的事件。但是,客户端可能需要进行多次往返才能完成 HTTP 请求。例如,在 URL 重定向的情况下,注册的钩子将根据客户端跟踪 HTTP 重定向的次数,进行多次调用,发出多个请求。用户负责在 http.Client
级别识别此类事件。下面的程序使用 http.RoundTripper
包装器识别当前请求。
package main import ( "fmt" "log" "net/http" "net/http/httptrace" ) // transport is an http.RoundTripper that keeps track of the in-flight // request and implements hooks to report HTTP tracing events. type transport struct { current *http.Request } // RoundTrip wraps http.DefaultTransport.RoundTrip to keep track // of the current request. func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { t.current = req return http.DefaultTransport.RoundTrip(req) } // GotConn prints whether the connection has been used previously // for the current request. func (t *transport) GotConn(info httptrace.GotConnInfo) { fmt.Printf("Connection reused for %v? %v\n", t.current.URL, info.Reused) } func main() { t := &transport{} req, _ := http.NewRequest("GET", "https://google.com", nil) trace := &httptrace.ClientTrace{ GotConn: t.GotConn, } req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace)) client := &http.Client{Transport: t} if _, err := client.Do(req); err != nil { log.Fatal(err) } }
该程序将跟踪 google.com 到 www.google.com 的重定向,并将输出
Connection reused for https://google.com? false
Connection reused for https://www.google.com/? false
net/http
包中的 Transport 支持 HTTP/1 和 HTTP/2 请求的追踪。
如果您是自定义 http.RoundTripper
实现的作者,您可以通过检查请求上下文中的 *httptest.ClientTrace
并根据事件发生情况调用相关的钩子来支持追踪。
结论
对于那些对调试 HTTP 请求延迟和编写用于出站流量网络调试的工具感兴趣的人来说,HTTP 追踪是对 Go 的宝贵补充。通过启用这种新功能,我们希望看到社区的 HTTP 调试、基准测试和可视化工具,例如 httpstat。
下一篇文章: Go 的七年
上一篇文章: 使用子测试和子基准测试
博客索引