Go 标准库的 http.Transport 默认仅支持通过 HTTP_PROXY 环境变量配置单个代理;若需轮询多个代理,必须自定义 Transport.Proxy 字段,替换默认的 http.ProxyFromEnvironment。
go 标准库的 `http.transport` 默认仅支持通过 `http_proxy` 环境变量配置单个代理;若需轮询多个代理,必须自定义 `transport.proxy` 字段,替换默认的 `http.proxyfromenvironment`。
在 Supervisor 中通过 http_proxy=... 设置环境变量(如你当前配置)只能指定唯一代理地址,无法原生支持代理列表轮询。Supervisor 本身不提供代理调度能力,它仅负责进程启停与环境注入。真正的代理路由逻辑必须由 Go 程序自身控制。
✅ 正确做法:在 Go 代码中绕过环境变量,手动构建支持轮询的 http.Transport。以下是一个简洁、线程安全的轮询代理示例:
package main
import (
"crypto/rand"
"fmt"
"math/big"
"net/http"
"net/url"
"sync"
"time"
)
// 代理列表(可从配置文件或环境变量动态加载)
var proxies = []string{
"http://user:pass@proxy1.example.com:8080",
"http://user:pass@proxy2.example.com:8080",
"http://user:pass@proxy3.example.com:8080",
}
var (
proxyMu sync.RWMutex
proxyIdx int
)
// roundRobinProxy 返回轮询式代理函数
func roundRobinProxy() func(*http.Request) (*url.URL, error) {
return func(req *http.Request) (*url.URL, error) {
proxyMu.Lock()
defer proxyMu.Unlock()
if len(proxies) == 0 {
return nil, fmt.Errorf("no proxy available")
}
u, err := url.Parse(proxies[proxyIdx])
if err != nil {
return nil, err
}
proxyIdx = (proxyIdx + 1) % len(proxies)
return u, nil
}
}
func main() {
// 创建自定义 Transport,禁用默认代理逻辑
transport := &http.Transport{
Proxy: roundRobinProxy(), // ✅ 关键:注入轮询逻辑
// 可选:设置超时、KeepAlive 等
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
client := &http.Client{Transport: transport}
// 示例请求(将自动使用轮询代理)
resp, err := client.Get("https://httpbin.org/ip")
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Printf("Request routed via proxy: %s\n", proxies[(proxyIdx-1+len(proxies))%len(proxies)])
}
⚠️ 注意事项:
- 不要删除 Supervisor 中的 http_proxy:虽不生效,但保留可避免其他依赖环境变量的组件异常;更推荐在 Go 启动脚本中显式清空该变量(如 env -u HTTP_PROXY /home/www/program -env prod),避免干扰。
- 代理健康检查:生产环境建议扩展轮询逻辑,加入失败重试、熔断或权重策略(例如使用 golang.org/x/net/proxy + 自定义 DialContext)。
- 并发安全:示例使用 sync.RWMutex 保障多 goroutine 下索引安全;高并发场景可考虑原子操作(atomic.Int64)或环形缓冲区优化。
- 配置解耦:代理列表应从配置文件(如 TOML/YAML)或环境变量(如 PROXY_LIST="p1,p2,p3")加载,避免硬编码。
总结:Supervisor 是进程管理工具,不具备网络层调度能力。代理轮询是应用层职责,必须在 Go 程序中通过自定义 http.Transport.Proxy 实现——这是唯一可靠、可控且符合 Go 生态惯例的方式。











