Go 忽略 HTTP_PROXY 环境变量
Go ignores HTTP_PROXY environment variable
我在整个互联网上都读到过,Go 读取 HTTP_PROXY
环境变量并为默认客户端设置代理。但是,它对我不起作用,我不知道为什么。
我在 Ubuntu 20.04,Go 是 1.16,所以我升级到 1.17 但还是一样。
我有下面的程序,我在终端中执行:HTTP_PROXY="http://localhost:8000" go run req.go
我看到第一个 Println
打印出正确的值,但未使用代理。
func main() {
fmt.Println(os.Getenv("HTTP_PROXY"))
client := &http.Client{}
resp, err := client.Get("http://localhost:8090/vm/1")
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
如果我修改代码并明确设置代理,它就可以工作。
u, err := url.Parse("http://localhost:8000")
if err != nil {
log.Fatal(err)
}
client := &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(u)},
}
我假设您有一个 NO_PROXY 变量设置为“localhost”,DefaultTransport 遵守该变量。
当使用 http.ProxyURL() 显式设置代理时,无论 NO_PROXY 如何使用此代理。
在深入研究源代码后,我找到了主要原因和解决方法。这是评论行为,但相当深刻。来源 opensource.google/x/net/http/httpproxy/proxy.go line 118 and on line 181 是准确的 if
这是负责任的。
问题是,当请求具有 URL localhost 或 127.x.x.x[= 时,HTTP_PROXY
会被忽略26=]。但是您可以轻松地将自定义 URI 添加到 /etc/hosts
或 C:\Windows\System32\drivers\etc\hosts
.
127.0.0.1 localserver.loc
然后所有请求都必须转到 localserver.loc:8090
而不是 localhost:8090
。它会像一个魅力。
对于其他遇到此问题的人,请确保您没有使用空结构初始化传输。这是 DefaultTransport(注意 Proxy
值):
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
DialContext: defaultTransportDialContext(&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}),
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
所以如果你要说这样的话:
if client.Transport == nil {
client.Transport = &http.Transport{}
}
不会使用代理。我的解决方法是:
if client.Transport == nil {
client.Transport = http.DefaultTransport.(*http.Transport).Clone()
}
我在整个互联网上都读到过,Go 读取 HTTP_PROXY
环境变量并为默认客户端设置代理。但是,它对我不起作用,我不知道为什么。
我在 Ubuntu 20.04,Go 是 1.16,所以我升级到 1.17 但还是一样。
我有下面的程序,我在终端中执行:HTTP_PROXY="http://localhost:8000" go run req.go
我看到第一个 Println
打印出正确的值,但未使用代理。
func main() {
fmt.Println(os.Getenv("HTTP_PROXY"))
client := &http.Client{}
resp, err := client.Get("http://localhost:8090/vm/1")
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
}
如果我修改代码并明确设置代理,它就可以工作。
u, err := url.Parse("http://localhost:8000")
if err != nil {
log.Fatal(err)
}
client := &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(u)},
}
我假设您有一个 NO_PROXY 变量设置为“localhost”,DefaultTransport 遵守该变量。
当使用 http.ProxyURL() 显式设置代理时,无论 NO_PROXY 如何使用此代理。
在深入研究源代码后,我找到了主要原因和解决方法。这是评论行为,但相当深刻。来源 opensource.google/x/net/http/httpproxy/proxy.go line 118 and on line 181 是准确的 if
这是负责任的。
问题是,当请求具有 URL localhost 或 127.x.x.x[= 时,HTTP_PROXY
会被忽略26=]。但是您可以轻松地将自定义 URI 添加到 /etc/hosts
或 C:\Windows\System32\drivers\etc\hosts
.
127.0.0.1 localserver.loc
然后所有请求都必须转到 localserver.loc:8090
而不是 localhost:8090
。它会像一个魅力。
对于其他遇到此问题的人,请确保您没有使用空结构初始化传输。这是 DefaultTransport(注意 Proxy
值):
var DefaultTransport RoundTripper = &Transport{
Proxy: ProxyFromEnvironment,
DialContext: defaultTransportDialContext(&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}),
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
所以如果你要说这样的话:
if client.Transport == nil {
client.Transport = &http.Transport{}
}
不会使用代理。我的解决方法是:
if client.Transport == nil {
client.Transport = http.DefaultTransport.(*http.Transport).Clone()
}