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

2 回复

我想我搞明白了。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_PROXYHTTPS_PROXYNO_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。

回到顶部