go x/net/http2:一旦连接,传输将忽略net/http.Transport.Proxy,

1u4esq0p  于 4个月前  发布在  Go
关注(0)|答案(7)|浏览(36)

你使用的Go版本是什么( go version )?

go1.10.2 darwin/amd64

这个问题在最新版本的发布中是否重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

GOARCH="amd64"
GOBIN=""
GOCACHE="..."
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="..."
GORACE=""
GOROOT="/usr/local/Cellar/go/1.10.2/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.10.2/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/_j/6wqhr8r57g34l96w0vt17bww0000gp/T/go-build671837991=/tmp/go-build -gno-record-gcc-switches -fno-common"

你做了什么?

我设置了一个HTTP2客户端和服务器。客户端向服务器发起几个并发请求。客户端的http.Transport有一个代理函数,用于修改请求的上下文。http.Transport.DisableKeepAlives标志也被设置为true。
收到响应后,打印出上下文的内容。
我的代码在playground: https://play.golang.org/p/bx4GvEZ-suw
由于HTTP/2包和所需的证书和密钥,无法在playground中运行。
要在文件所在目录中获取证书+密钥,请运行: openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.pem -days 365 -nodes

你期望看到什么?

每个请求的上下文都被修改,如下所示:(如果http.Transport没有配置HTTP2会发生什么)

context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)
context.Background.WithValue("Proxy", 1)

你看到了什么?

几乎所有的请求都没有通过http.Transport.Proxy函数,尽管已经设置了no keepalives标志:

context.Background.WithValue("Proxy", 1)
context.Background
context.Background.WithValue("Proxy", 1)
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background
context.Background

在客户端不使用HTTP2似乎可以完全解决这个问题。尝试在服务器上调整10ms的处理时间和启动goroutine之间的10ms等待时间,可以解决这个问题或者使问题变得更糟。然而,这并不是你在生产环境中应该控制的事情。
这可能与: #25620 有关,但是那个问题是在TCP级别上发生的(在那里调用了http.Transport.Proxy,但没有被尊重),而在这里函数根本没有被调用。

e5njpo68

e5njpo681#

(CC: @bradfitz 和 @tombergan 为 x/net/http2。)

vc6uscn9

vc6uscn92#

tl;dr net/http在RoundTrip未委托给备用round tripper时执行Proxy。当备用RT来自x/net/http2时,似乎从未调用过Proxy(没有引用到Proxy),我认为这需要修复。

如果你使用GODEBUG=http2debug=1,你看到"http2:没有可用的缓存连接"的次数应该等于你看到期望的"context.Background.WithValue("Proxy", 1)"的次数。当还没有缓存的h2连接匹配时,net/http会在创建连接之前执行connectMethodForRequestconnectMethodForRequest是我唯一看到Proxy被调用的地方——我看不到在x/net/http2中调用Proxy。如果h2连接池确实有一个连接匹配,它将运行自己的RoundTrip。

更多详情请查看:幻灯片A,幻灯片B,Video。此外,我认为DisableKeepAlive对使用长寿命连接的http2没有任何影响。

az31mfrm

az31mfrm3#

@meirf

此外,我认为DisableKeepAlive对使用长连接的http2没有影响。实际上,这里已经实现了这个功能,尽管连接在空闲时立即关闭:#14008

thigvfpy

thigvfpy5#

这可能很难用当前两个包之间的接口来修复。需要一些思考。最坏的情况是我们至少可以记录下来,但我更愿意去修复它。

92vpleto

92vpleto6#

这个问题仍然存在(go1.20.1版本)。
我们正在使用不同的代理向相同的目标服务器(例如https://api.myip.com/)发送请求。在HTTP/1.1中,这种方式可以正常工作,但在使用HTTP/2时,所有请求都只使用一个代理(因为net/http会重用已经打开到目标服务器的连接,并忽略代理配置之间的差异)。
此外,https://pkg.go.dev/net/http@go1.20.1#Transport 中的“ForceAttemptHTTP2”描述中提到,如果提供了“非零的Dial、DialTLS或DialContext func或TLSClientConfig”,HTTP/2将被“谨慎地禁用”,但是我提供了TLSClientConfig和DialContext,而net/http仍然在使用HTTP/2(我应该为此开一个单独的问题吗?)。
可能的解决方法(禁用HTTP/2):

client.Transport.TLSNextProto = make(map[string]func(authority string, c *tls.Conn) http.RoundTripper)
puruo6ea

puruo6ea7#

顺便问一下,有没有其他方法可以在不禁用HTTP/2的情况下解决这个问题?

相关问题