Go的HTTP请求即使将force attempt设置为false,仍会回退到HTTP2。

huangapple go评论161阅读模式
英文:

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

问题

有一个奇怪的问题,每隔几个请求,Go的http包会抛出以下错误:

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

我发现默认的传输设置了ForceAttemptHTTP2true(https://golang.org/src/net/http/transport.go 第48行),所以我手动将其设置为false,如下所示:

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

但是即使这样做了,我仍然得到相同的http2错误,而不是http1,这对我来说没有意义。

我对网络不太了解,所以我觉得我可能漏掉了一些显而易见的东西?

我想问的问题是如何强制http包只使用http而不是http2

英文:

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

得分: 5

这似乎可以实现:

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")
}

> 必须禁用HTTP/2的程序可以通过将Transport.TLSNextProto(对于客户端)或Server.TLSNextProto(对于服务器)设置为非nil的空映射来实现。

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

诚然,这种语法相当笨拙,所以你可能更喜欢下面这种方式:

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")
}
英文:

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")
}

huangapple
  • 本文由 发表于 2021年5月31日 17:06:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/67770829.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定