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

1

5

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

Klemm answered 31/5, 2021 at 9:6 Comment(4)
Not forcing HTTP/2 is not the same as disabling HTTP/2.Mcgaha
Does this answer your question? https://mcmap.net/q/1444796/-how-to-disable-http-2-using-server-tlsnextproto/13860Mcgaha
Could you give me some more information on that? I'm not sure how I can apply that to an HTTP ClientKlemm
Yeah, good point. I'm not exactly sure how to translate that to the client, either.Mcgaha
M
6

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")
}
Mnemonic answered 31/5, 2021 at 13:53 Comment(2)
3rd (not less clunky) way: go build -tags nethttpomithttp2.Kell
Thank you! This is what I was looking for!Klemm

© 2022 - 2024 — McMap. All rights reserved.