为什么 Go 会对 localhost 绕过代理
区分 Go 内置的回环地址绕过规则与 NO_PROXY 配置,并比较环境变量路由和显式 ProxyURL 的行为。
Go 的环境代理选择器对 localhost 和回环 IP 目标有内置例外。清空 NO_PROXY 并不会移除这个例外。因此,本地测试可能直连,而对公共主机名的请求仍按预期使用代理。
这条规则针对的是请求目标。它并不妨碍你使用自身地址为 127.0.0.1 的代理监听端。
不发送请求,直接检查选择器
package main
import (
"fmt"
"net/http"
"net/url"
)
func main() {
fixed, _ := url.Parse("http://203.0.113.10:8080")
for _, target := range []string{
"http://localhost:8000/",
"http://127.0.0.1:8000/",
"http://example.com/",
} {
request, _ := http.NewRequest("GET", target, nil)
discovered, err := http.ProxyFromEnvironment(request)
explicit, _ := http.ProxyURL(fixed)(request)
fmt.Println(target, discovered, explicit, err)
}
}
如果想观察环境配置的对比结果,请在为进程设置好代理变量后运行。这个程序只计算选择器的结果,不会连接文档中的代理或任何目标。
环境自动发现与显式选择器采用不同策略
ProxyFromEnvironment 会考虑目标协议、环境设置和绕过规则,包括它对回环地址的特殊处理。ProxyURL 则会为传给该选择器的每个请求返回所提供的代理 URL。
因此,使用显式 ProxyURL 的专用 transport 可以将发往本地目标的请求送入代理。只有代理能够正当地访问所请求的目标时,这样做才有用。远程代理的 localhost 并不是你笔记本电脑的 localhost,所以强制走这条路由未必是有用的连通性测试。
在进程缓存环境配置之前检查
标准 net/http 的环境代理配置在首次使用后会被缓存。随后在同一个运行中的程序内修改环境变量,并不是重新进行全新配置测试的可靠方式。请用预期值启动新进程,或提供一个行为由你控制的显式选择器。
这里的回环行为适用于 Go 1.27.3 的标准代理选择器。其他语言和 HTTP 客户端可能采用不同的 localhost 路由规则。