Go的http.Client默认不走代理,必须显式配置Transport.Proxy或使用http.ProxyFromEnvironment读取HTTP_PROXY等环境变量;固定代理用http.ProxyURL,动态分流需自定义Proxy函数,SOCKS5则须替换Dial而非仅设Proxy。

Go 的 http.Client 默认不走代理,必须显式配置 Transport.Proxy 或依赖环境变量,否则即使系统或浏览器开了代理,Go 程序仍直连失败。
用 http.ProxyURL 设置固定 HTTP/HTTPS 代理
适用于需要硬编码代理地址、带认证、或绕过环境变量的场景。注意 url.Parse 必须传入完整协议+主机+端口,用户名密码需 URL 编码(如含特殊字符)。
-
http.ProxyURL只接受*url.URL,不能传字符串;解析失败时返回nil,需检查错误 - 代理 URL 中含认证时写成
"http://user:pass@proxy.example.com:8080",Go 会自动提取并透传 - 若代理仅支持 HTTPS 请求(如某些企业网关),
http.ProxyURL仍可工作,但目标请求的req.URL.Scheme决定是否走 CONNECT 隧道 - 不支持 SOCKS5 —— 这类协议需换用
golang.org/x/net/proxy的SOCKS5dialer 替换Transport.Dial
示例片段:
proxyURL, _ := url.Parse("http://user:pass@127.0.0.1:7897")
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
},
}
用 http.ProxyFromEnvironment 读取环境变量
这是最轻量、最符合 Unix 哲学的方式,但行为完全由环境变量驱动,容易因拼写、大小写、空格或 NO_PROXY 规则导致静默失效。
- Go 读取的是
HTTP_PROXY/HTTPS_PROXY(全大写),http_proxy等小写形式在部分 Go 版本中不被识别 -
NO_PROXY支持逗号分隔的域名或 IP 段,如"localhost,127.0.0.1,.example.com";注意开头的点表示子域名匹配 - 如果设置了
ALL_PROXY,它会在HTTP_PROXY和HTTPS_PROXY均未设置时 fallback 使用 - 该函数内部调用
golang.org/x/net/http/httpproxy.FromEnvironment(),所以必须确保该包已导入(Go 1.22+ 已内置,旧版本需显式引入)
常见错误现象:Get "https://api.github.com": context deadline exceeded,但 curl -x http://127.0.0.1:7897 https://api.github.com 正常 → 很可能是环境变量名写成了 http_proxy 而非 HTTP_PROXY。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
自定义代理选择函数:按 Host 或路径分流
当部分请求要走代理、部分要直连(比如内网服务不走代理),不能只靠 NO_PROXY,得自己写逻辑。
- 函数签名必须是
func(*http.Request) (*url.URL, error),返回nil, nil表示不使用代理(即直连) - 判断依据优先用
req.URL.Host,不是req.Host(后者可能被中间件篡改) - 若需匹配子域名,别用
strings.HasSuffix硬比对,推荐用strings.TrimPrefix(req.URL.Host, ".")+ 列表查表,避免误判notexample.com匹配example.com - 返回错误会导致整个请求失败,不要在函数里 panic 或忽略认证失败
典型写法:
Proxy: func(req *http.Request) (*url.URL, error) {
if strings.HasSuffix(req.URL.Host, ".internal.company") {
return nil, nil // 直连
}
if req.URL.Host == "duckduckgo.com" {
return url.Parse("http://127.0.0.1:7897")
}
return http.ProxyFromEnvironment(req)
}
SOCKS5 代理必须替换 Dial,不能只设 Proxy
http.Transport.Proxy 只处理 HTTP/HTTPS 代理协商,SOCKS5 是传输层协议,Go 标准库不原生支持,必须用第三方 dialer。
- 必须导入
golang.org/x/net/proxy,且调用proxy.SOCKS5创建 dialer - 创建 transport 时,**不能**再设
Proxy字段,否则会冲突;应清空Proxy: nil,只靠DialContext或Dial发起连接 -
proxy.Direct是关键参数,表示“无法通过 SOCKS5 连接时,降级为直连”,否则遇到不支持 SOCKS5 的目标会直接报错 - SOCKS5 不处理 HTTPS 的 CONNECT 隧道建立逻辑,这部分仍由
http.Transport自动完成,所以对用户透明
漏掉 proxy.Direct 是最常踩的坑:程序会卡在 DNS 解析或 dial 阶段,错误信息类似 dial tcp: i/o timeout,而非明确的 SOCKS5 协议错误。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










