go构建时走代理但运行时不走代理,因go命令受http_proxy等环境变量影响,而业务代码需显式配置http.client.transport.proxy。

Go build 时走代理但运行时不走代理?
Go 的 go build 和 go get 默认会通过环境变量控制 HTTP 客户端行为,但运行时程序是否走代理,完全取决于你代码里怎么写——Go 标准库的 http.DefaultClient 不读取系统代理,也不会自动继承 HTTP_PROXY 环境变量。
常见错误现象:go get golang.org/x/sync 成功,但自己写的 HTTP 请求仍超时;或本地测试走代理,部署到服务器后请求失败。
- 真正生效的代理控制点只有两个:环境变量(影响
go命令自身)和代码中显式配置http.Client.Transport.Proxy -
HTTP_PROXY、HTTPS_PROXY、NO_PROXY只对 Go 工具链(如go mod download)有效,不影响你的业务代码 - 若想让业务 HTTP 请求走代理,必须手动设置:
http.DefaultClient.Transport = &http.Transport{ Proxy: http.ProxyURL(&url.URL{Scheme: "http", Host: "127.0.0.1:7890"}), }
GO111MODULE=on 时 proxy 配置在哪生效?
模块代理(GOPROXY)只影响 go mod download、go get 等模块拉取行为,和网络请求代理是两套机制,别混用。
使用场景:国内拉不到 golang.org 下的包,或私有模块需要经由 Nexus/Artifactory 中转。
立即学习“go语言免费学习笔记(深入)”;
-
GOPROXY是逗号分隔列表,按顺序尝试,支持direct表示直连,off表示禁用代理 - 推荐配置:
GOPROXY=https://goproxy.cn,direct(注意末尾direct,否则私有域名无法解析) - 若公司内网有自建代理,确保
GOPROXY值以https://开头,且证书可信;否则会报错:proxyconnect tcp: tls: first record does not look like a TLS handshake
如何让 go test 或 go run 临时走代理?
开发调试时经常要临时切代理,但又不想改全局环境变量污染终端会话。最干净的方式是命令前加环境变量前缀。
参数差异:HTTP_PROXY 控制 HTTP 请求,HTTPS_PROXY 控制 HTTPS 请求,NO_PROXY 指定不走代理的域名(逗号分隔,支持 * 通配,但 Go 1.19+ 才支持,旧版本只认完整域名)
- 临时启用:
HTTP_PROXY=http://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 go run main.go
- 排除内网地址:
NO_PROXY=localhost,127.0.0.1,.example.com go test ./...
- 注意大小写:Windows 的
set HTTP_PROXY=...无效,必须用 PowerShell 的$env:HTTP_PROXY="..."或 CMD 的set HTTP_PROXY=...(但仅当前命令生效)
goroutine 多发请求时代理配置的并发安全问题
很多人直接改 http.DefaultClient,结果在高并发下出现连接复用混乱、代理配置被覆盖、TLS 握手失败等问题。
性能影响:共享一个 http.Client 是合理的,但它的 Transport 必须是线程安全的;而直接赋值 Transport 后再修改其字段(比如动态改 Proxy)不是安全操作。
- 正确做法是为每个需不同代理策略的逻辑创建独立
http.Client实例 - 若所有请求都走同一代理,初始化一次即可:
client := &http.Client{ Transport: &http.Transport{ Proxy: http.ProxyURL(&url.URL{Scheme: "http", Host: "127.0.0.1:7890"}), }, } - 别在 goroutine 里反复 new
http.Transport,它本身开销大;也别在运行时修改已启动 client 的Transport.Proxy字段
HTTP_PROXY 就万事大吉,结果业务 HTTP 请求根本没走过去——因为那行代码压根没配 Client。










