Today I was investigating why HTTP redirects resulted in more persistent connections staying open than I was expecting. I found myself digging around deep inside net/http/transport.go and I noticed the new net/http/httptrace package. It is new in Go 1.7, which is currently in beta.
net/http/httptrace is lightly documented, and because it is new, there are no examples to look at. So I decided to share what I came up with here.
package main import ( "context" "fmt" "log" "net/http" "net/http/httptrace" "os" ) func main() { ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{ PutIdleConn: func(err error) { if err == nil { fmt.Println("put idle: no err") } else { fmt.Println("put idle:", err.Error()) } }, }) req, err := http.NewRequest("GET", "http://www.golang.org/", nil) if err != nil { log.Fatal("new req", err) } req = req.WithContext(ctx) _, err = http.DefaultClient.Do(req) if err != nil { fmt.Fprintf(os.Stderr, "fetch: %v\n", err) os.Exit(1) } }
The key things I had to figure out (and hopefully you won’t have to since you found this post) were:
- How to get a base context to add the tracer to (context.Background())
- Which callback to use in the ClientTrace structure (for my purposes, PutIdleConn)
- How to do an HTTP request with the context attached (NewRequest -> req.WithContext -> http.(*Client).Do)
If you are used to using the simple http.(*Client).Get method to do HTTP you’ll need to learn to use http.NewRequest in order to make a request object, and then pass that to a client. In this simple case, I used the DefaultClient. In a library, you should be using the http.Client passed into you by the caller, so that your library would work in contexts like Google App Engine.
Leave a Reply