Go http request falls back to http2 even when force attempt is set to false

Viewed 1650

There this weird thing that keeps happening every few requests where Go's http package throws the following error:

http2: server sent GOAWAY and closed the connection; LastStreamID=19999, ErrCode=NO_ERROR, debug=""

And so I realised that the default transport has ForceAttemptHTTP2 set to true(https://golang.org/src/net/http/transport.go line 48), so I manually set that to false like below:

    transport := &http.Transport{
        ForceAttemptHTTP2: false,
    }
    httpClient := &http.Client{Transport: transport}

But even after doing that, I still get the same http2 error instead of http1, which is not making sense to me?

I'm new to networking so I have a feeling I'm missing something that should be obvious here?

I guess the question would be how do I force the http package to only use http and not http2

1 Answers

This seems to do it:

package main

import (
   "crypto/tls"
   "net/http"
)

func main() {
   client := &http.Client{
      Transport: &http.Transport{
         TLSNextProto: map[string]func(string, *tls.Conn)http.RoundTripper{},
      },
   }
   req, e := http.NewRequest("HEAD", "https://stackoverflow.com", nil)
   if e != nil {
      panic(e)
   }
   res, e := client.Do(req)
   if e != nil {
      panic(e)
   }
   println(res.Proto == "HTTP/1.1")
}

Programs that must disable HTTP/2 can do so by setting Transport.TLSNextProto (for clients) or Server.TLSNextProto (for servers) to a non-nil, empty map.

https://golang.org/pkg/net/http#pkg-overview

Admittedly, this is pretty awkward syntax, so you might prefer something like this instead:

package main

import (
   "net/http"
   "os"
)

func main() {
   os.Setenv("GODEBUG", "http2client=0")
   req, e := http.NewRequest("HEAD", "https://stackoverflow.com", nil)
   if e != nil {
      panic(e)
   }
   res, e := new(http.Client).Do(req)
   if e != nil {
      panic(e)
   }
   println(res.Proto == "HTTP/1.1")
}
Related