Search code examples
httpgohttp2

Confusion over Go's http2 implementation


I run tons of traffic over SSL. I was thinking of speeding up these calls by using a http2 client. However, I'm hesitant to do so because it feels like i have less control on how it behaves.

Here is a production client using Go's basic net/http

ClientHTTP := &http.Client{
    Transport: &http.Transport{
        Proxy: http.ProxyFromEnvironment,
        Dial: (&net.Dialer{
            Timeout:   timeout * time.Second,
            KeepAlive: 1 * time.Minute,
        }).Dial,
        TLSHandshakeTimeout: timeout * time.Second,
        MaxIdleConns:        3000,
        MaxIdleConnsPerHost: 3000,
        IdleConnTimeout:     60 * time.Second,
    },
    Timeout: timeout * time.Second,
}

As far as I can tell I have way less control on the transport.

ClientHTTP2 := &http.Client{
    Transport: &http2.Transport{
        AllowHTTP: true,
    },
    Timeout: timeout * time.Second,
}

Is there anything I'm missing? Is http2 production ready? I understand that http2 uses a single TCP connection and therefore things likes pools go away. Yet it somehow feels incomplete. Will these behave the same way as the production client? Is there a better way to implement ClientHTTP2 and lastly, AllowHTTP doesn't seem to do anything. In the case where there might be an http call I thought I'd be able to able it safely, but instead it errors out.


Solution

  • http.Transport supports HTTP2, however you have to configure the more modern DialContext, not Dial (which is deprecated):

    package main
    
    import (
            "fmt"
            "net"
            "net/http"
            "net/http/httputil"
            "time"
    )
    
    func main() {
            c := &http.Client{
                    Transport: &http.Transport{
                            Proxy: http.ProxyFromEnvironment,
                            DialContext: (&net.Dialer{ // use DialContext here
                                    Timeout:   10 * time.Second,
                                    KeepAlive: 1 * time.Minute,
                            }).DialContext,
                            TLSHandshakeTimeout: 10 * time.Second,
                            MaxIdleConns:        3000,
                            MaxIdleConnsPerHost: 3000,
                            IdleConnTimeout:     60 * time.Second,
                    },
                    Timeout: 1 * time.Second,
            }
            res, _ := c.Get("https://http2.akamai.com/")
            b, _ := httputil.DumpResponse(res, false)
            fmt.Println(string(b))
    }
    
    // HTTP/2.0 200 OK
    // Content-Length: 11928
    // Accept-Ch: DPR, Width, Viewport-Width, Downlink, Save-Data
    // Access-Control-Allow-Credentials: false
    // ...
    

    The only reason to use http2.Transport is to skip the initial connection upgrade (aka. prior knowledge). If that is not a concern, stick to the standard client and transport.