Golang中x/net/proxy和FromEnvironmentUsing(dialer)的使用问题
Golang中x/net/proxy和FromEnvironmentUsing(dialer)的使用问题
我尝试通过代理发送流量,但代码似乎没有读取环境变量。我甚至添加了在代码中看到的 all_proxy。
set | grep proxy
all_proxy=http://localhost:3128 https_proxy=http://localhost:3128 no_proxy=‘localhost, 127.0.0.1’
我也设置了 http_proxy。
我遇到了这个错误,并且没有尝试访问代理。
proxyDialer.Dial panic: dial tcp 142.250.200.36:443: i/o timeout
goroutine 1 [running]: main.main() /src/moelma/go-test/dialertest.go:23 +0x20e
strace 显示直接连接尝试。
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 6 connect(6, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr(“142.250.200.36”)}, 16) = -1 EINPROGRESS (Operation now in progress)
package main
import (
"crypto/tls"
"net"
"time"
"fmt"
"golang.org/x/net/proxy"
"os"
"strings"
)
func main() {
dialer := &net.Dialer{
Timeout : 20 * time.Millisecond,
}
proxyDialer := proxy.FromEnvironmentUsing(dialer)
conn, err := proxyDialer.Dial("tcp", "www.google.com:443")
if err != nil {
fmt.Println("proxyDialer.Dial")
panic(err)
}
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: false})
if strings.Contains(err.Error(), "timed out") {
fmt.Println("Connection timed out")
os.Exit(2)
} else {
if err == nil {
conn.Close()
}
}
}
更多关于Golang中x/net/proxy和FromEnvironmentUsing(dialer)的使用问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我想我搞明白了。net/proxy 库只将socks作为协议方案。要添加一个“connect”方案,必须进行定义。
例如,使用:
"github.com/wrouesnel/go.connect-proxy-scheme"
proxy.RegisterDialerType("http", connect_proxy_scheme.ConnectProxy)
如果能把 connect 方案包含进 net/proxy 库中,那就太好了!
更多关于Golang中x/net/proxy和FromEnvironmentUsing(dialer)的使用问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
从你的代码和错误信息来看,问题在于 proxy.FromEnvironmentUsing() 没有正确读取环境变量中的代理设置。根据 golang.org/x/net/proxy 包的实现,它默认只读取 HTTP_PROXY、HTTPS_PROXY 和 NO_PROXY 环境变量,而不包括 all_proxy。
以下是修正后的代码示例:
package main
import (
"crypto/tls"
"fmt"
"net"
"net/url"
"os"
"time"
"golang.org/x/net/proxy"
)
func main() {
// 明确设置环境变量名(如果需要)
os.Setenv("HTTP_PROXY", "http://localhost:3128")
os.Setenv("HTTPS_PROXY", "http://localhost:3128")
dialer := &net.Dialer{
Timeout: 5 * time.Second, // 增加超时时间
}
proxyDialer := proxy.FromEnvironmentUsing(dialer)
// 测试连接
conn, err := proxyDialer.Dial("tcp", "www.google.com:443")
if err != nil {
fmt.Printf("proxyDialer.Dial error: %v\n", err)
// 回退到直接连接测试代理是否工作
directConn, directErr := net.DialTimeout("tcp", "localhost:3128", 5*time.Second)
if directErr != nil {
fmt.Printf("Direct proxy connection failed: %v\n", directErr)
} else {
directConn.Close()
fmt.Println("Proxy is reachable directly")
}
os.Exit(1)
}
defer conn.Close()
// TLS握手
tlsConn := tls.Client(conn, &tls.Config{
ServerName: "www.google.com",
})
defer tlsConn.Close()
tlsErr := tlsConn.Handshake()
if tlsErr != nil {
fmt.Printf("TLS handshake error: %v\n", tlsErr)
os.Exit(1)
}
fmt.Println("Successfully connected through proxy")
}
如果你需要支持 all_proxy 环境变量,可以手动处理:
package main
import (
"crypto/tls"
"fmt"
"net"
"net/url"
"os"
"time"
"golang.org/x/net/proxy"
)
func createProxyDialer() (proxy.Dialer, error) {
dialer := &net.Dialer{
Timeout: 5 * time.Second,
}
// 优先检查 all_proxy
if proxyURL := os.Getenv("all_proxy"); proxyURL != "" {
parsedURL, err := url.Parse(proxyURL)
if err != nil {
return nil, fmt.Errorf("parse proxy URL: %w", err)
}
proxyDialer, err := proxy.FromURL(parsedURL, dialer)
if err != nil {
return nil, fmt.Errorf("create proxy from URL: %w", err)
}
return proxyDialer, nil
}
// 回退到标准环境变量
return proxy.FromEnvironmentUsing(dialer), nil
}
func main() {
proxyDialer, err := createProxyDialer()
if err != nil {
fmt.Printf("Failed to create proxy dialer: %v\n", err)
os.Exit(1)
}
conn, err := proxyDialer.Dial("tcp", "www.google.com:443")
if err != nil {
fmt.Printf("Connection failed: %v\n", err)
os.Exit(1)
}
defer conn.Close()
tlsConn := tls.Client(conn, &tls.Config{
ServerName: "www.google.com",
})
defer tlsConn.Close()
if err := tlsConn.Handshake(); err != nil {
fmt.Printf("TLS handshake failed: %v\n", err)
os.Exit(1)
}
fmt.Println("Successfully connected through proxy")
}
调试代理设置的辅助函数:
func debugProxySettings() {
envVars := []string{
"HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY",
"http_proxy", "https_proxy", "no_proxy",
"all_proxy", "ALL_PROXY",
}
fmt.Println("Current proxy environment variables:")
for _, env := range envVars {
if val := os.Getenv(env); val != "" {
fmt.Printf(" %s=%s\n", env, val)
}
}
}
在你的原始代码中,20毫秒的超时时间太短,特别是通过代理连接时。另外,错误处理逻辑在 conn 创建后检查错误,这会导致 panic。

