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 localhost127.x.x.x[= 时,HTTP_PROXY 会被忽略26=]。但是您可以轻松地将自定义 URI 添加到 /etc/hostsC:\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()
}