英文:
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)},
}
英文:
I read all over the internet, that Go reads HTTP_PROXY
environment variable and set proxy for default client. However, it is not working for me and I don't know why.
I'm on Ubuntu 20.04, Go was 1.16, so I upgraded to 1.17 but it still the same.
I have the program below and I execute this in terminal: HTTP_PROXY="http://localhost:8000" go run req.go
I see that first Println
prints out correct value, but proxy is not used.
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))
}
If I modify the code, and set proxy explicitly, it works.
u, err := url.Parse("http://localhost:8000")
if err != nil {
log.Fatal(err)
}
client := &http.Client{
Transport: &http.Transport{Proxy: http.ProxyURL(u)},
}
答案1
得分: 4
在查看源代码后,我找到了主要原因和一个解决方法。这是一种被注释掉的行为,但非常深入。源代码中的 opensource.google/x/net/http/httpproxy/proxy.go 第118行 和 第181行 是负责的确切 if
语句。
问题是,当请求的URL为 localhost 或 127.x.x.x 时,HTTP_PROXY
被忽略。但你可以将自定义的URI添加到 /etc/hosts
或 C:\Windows\System32\drivers\etc\hosts
中。
127.0.0.1 localserver.loc
然后,所有的请求都必须发送到 localserver.loc:8090
而不是 localhost:8090
。这样就能正常工作了。
英文:
After digging in the source code I have found the main reason and also a workaround. It is commented behavior, but quite deep. Source opensource.google/x/net/http/httpproxy/proxy.go line 118 and on line 181 is exact if
which is responsible.
The issue is, that HTTP_PROXY
is ignored when the request has URL localhost or 127.x.x.x. But you can easily add custom URI to /etc/hosts
or C:\Windows\System32\drivers\etc\hosts
.
127.0.0.1 localserver.loc
Then all requests must go to localserver.loc:8090
not localhost:8090
. And it will work like a charm.
答案2
得分: 1
我假设你设置了一个名为"NO_PROXY"的变量,其值为"localhost",这个值会被DefaultTransport所遵循。
当使用http.ProxyURL()来显式设置代理时,无论NO_PROXY的值如何,都会使用这个代理。
英文:
I assume that you have a NO_PROXY variable set to "localhost", which is respected by the DefaultTransport.
When explicitely setting a Proxy with http.ProxyURL(), this proxy is used regardless of NO_PROXY.
答案3
得分: 1
对于其他遇到此问题的人,请确保您没有使用空结构初始化传输。这是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()
}
英文:
For anyone else stumbling on this, be sure that you didn't initialize transport with an empty struct. Here's the DefaultTransport (note the Proxy
value):
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,
}
So if you were to say something like:
if client.Transport == nil {
client.Transport = &http.Transport{}
}
the proxy wouldn't be used. The fix for me was:
if client.Transport == nil {
client.Transport = http.DefaultTransport.(*http.Transport).Clone()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论