Pular para o conteúdo
Guides 9 min de leitura 969 visualizações

Usando proxies em Go (Golang)

Conheça o essencial do uso de proxies HTTP e SOCKS em Go (Golang). Este guia cobre instalação, configuração e casos de uso práticos para uma rede segura e anônima.

Usando proxies em Go (Golang)

Usar proxies em Go envolve configurar o http.Transport de um http.Client com uma função Proxy, normalmente http.ProxyURL para proxies estáticos ou uma função personalizada para seleção dinâmica de proxy.

Por que usar proxies em Go?

Os proxies servem a diversos propósitos na comunicação de rede, especialmente ao fazer requisições HTTP a partir de aplicações Go:

  • Anonimato: mascarar o endereço IP original do cliente.
  • Segmentação geográfica: acessar conteúdos ou serviços restritos a regiões geográficas específicas, roteando as requisições por proxies localizados nessas regiões.
  • Limites de requisição: distribuir requisições entre vários endereços IP para evitar atingir os limites de taxa impostos pelos servidores de destino.
  • Web scraping: viabilizar a coleta de dados em larga escala com rotação de endereços IP, contornando a detecção e gerenciando o volume de requisições.
  • Segurança e filtragem: rotear o tráfego por proxies corporativos para varredura de segurança, filtragem de conteúdo ou controle de acesso.
  • Depuração: interceptar e inspecionar o tráfego.

Configurando um cliente HTTP com proxy

O pacote net/http da biblioteca padrão do Go oferece suporte robusto a configurações de proxy. O mecanismo principal consiste em modificar o http.Transport associado a um http.Client.

Usando http.ProxyFromEnvironment

A forma mais simples de usar um proxy é aproveitar as variáveis de ambiente. A função http.ProxyFromEnvironment do Go verifica as variáveis de ambiente HTTP_PROXY, HTTPS_PROXY e NO_PROXY.

  • HTTP_PROXY: usada para requisições http://.
  • HTTPS_PROXY: usada para requisições https://.
  • NO_PROXY: uma lista de hostnames separados por vírgula que devem ignorar o proxy.
package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "time"
)

func main() {
    // Set environment variables (for demonstration)
    os.Setenv("HTTP_PROXY", "http://your_proxy_ip:port")
    os.Setenv("HTTPS_PROXY", "http://your_proxy_ip:port") // Note: HTTPS_PROXY can be an HTTP proxy
    // os.Setenv("NO_PROXY", "localhost,127.0.0.1")

    client := &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyFromEnvironment,
        },
        Timeout: 10 * time.Second,
    }

    resp, err := client.Get("http://httpbin.org/ip")
    if err != nil {
        fmt.Printf("Error making request: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response body: %v\n", err)
        return
    }
    fmt.Printf("Response from httpbin.org/ip:\n%s\n", body)

    os.Unsetenv("HTTP_PROXY")
    os.Unsetenv("HTTPS_PROXY")
}

Usando http.ProxyURL para proxies estáticos

Para configuração explícita de proxy, usa-se http.ProxyURL. Essa função recebe um *url.URL que representa o endereço do proxy.

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "time"
)

func main() {
    proxyStr := "http://your_proxy_ip:port" // Replace with your proxy address
    proxyURL, err := url.Parse(proxyStr)
    if err != nil {
        fmt.Printf("Error parsing proxy URL: %v\n", err)
        return
    }

    client := &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyURL(proxyURL),
        },
        Timeout: 10 * time.Second,
    }

    resp, err := client.Get("http://httpbin.org/ip")
    if err != nil {
        fmt.Printf("Error making request: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response body: %v\n", err)
        return
    }
    fmt.Printf("Response from httpbin.org/ip:\n%s\n", body)
}

Autenticação de proxy

Muitos proxies exigem autenticação. Para proxies HTTP/HTTPS que usam Basic Authentication, as credenciais podem ser embutidas diretamente na URL do proxy:

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "time"
)

func main() {
    // Format: "http://username:password@proxy_ip:port"
    proxyStr := "http://user:password@your_auth_proxy_ip:port" // Replace with your authenticated proxy
    proxyURL, err := url.Parse(proxyStr)
    if err != nil {
        fmt.Printf("Error parsing proxy URL: %v\n", err)
        return
    }

    client := &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyURL(proxyURL),
        },
        Timeout: 10 * time.Second,
    }

    resp, err := client.Get("http://httpbin.org/ip")
    if err != nil {
        fmt.Printf("Error making request with authenticated proxy: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response body: %v\n", err)
        return
    }
    fmt.Printf("Response from httpbin.org/ip via authenticated proxy:\n%s\n", body)
}

Usando proxies SOCKS5

Embora net/http dê suporte direto a proxies HTTP/HTTPS, proxies SOCKS5 exigem um pacote adicional: golang.org/x/net/proxy. O SOCKS5 opera em um nível mais baixo que os proxies HTTP, dando suporte a diversos protocolos.

Para usar um proxy SOCKS5, você precisa criar um Dialer com o pacote proxy e atribuí-lo ao campo DialContext do http.Transport.

package main

import (
    "context"
    "fmt"
    "io"
    "net"
    "net/http"
    "time"

    "golang.org/x/net/proxy" // Make sure to 'go get golang.org/x/net/proxy'
)

func main() {
    socks5Proxy := "socks5://user:password@your_socks5_proxy_ip:port" // Replace with your SOCKS5 proxy

    dialer, err := proxy.SOCKS5("tcp", socks5Proxy[len("socks5://"):], nil, proxy.Direct) // Basic auth is handled by the dialer
    if err != nil {
        fmt.Printf("Error creating SOCKS5 dialer: %v\n", err)
        return
    }

    // For authenticated SOCKS5, the proxy.SOCKS5 function handles it if the URL contains credentials.
    // If the proxy.SOCKS5 function doesn't parse credentials directly, you might need to
    // extract them and pass a proxy.Auth struct. Example:
    // auth := &proxy.Auth{User: "user", Password: "password"}
    // dialer, err := proxy.SOCKS5("tcp", "your_socks5_proxy_ip:port", auth, proxy.Direct)

    client := &http.Client{
        Transport: &http.Transport{
            DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
                return dialer.Dial(network, addr)
            },
            // Optionally, set TLSClientConfig for HTTPS over SOCKS5
            // TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // Use with caution
        },
        Timeout: 10 * time.Second,
    }

    resp, err := client.Get("http://httpbin.org/ip")
    if err != nil {
        fmt.Printf("Error making request with SOCKS5 proxy: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response body: %v\n", err)
        return
    }
    fmt.Printf("Response from httpbin.org/ip via SOCKS5 proxy:\n%s\n", body)
}

Seleção dinâmica e rotação de proxies

Em aplicações como web scraping ou coleta de dados em larga escala, a rotação de proxies é essencial para evitar bloqueios de IP e gerenciar o volume de requisições. Isso exige uma função Proxy personalizada para o http.Transport.

O campo Proxy do http.Transport espera uma função com a assinatura func(*http.Request) (*url.URL, error). Essa função é chamada antes de cada requisição, permitindo a seleção dinâmica de proxy com base nas propriedades da requisição ou em uma estratégia de rotação.

package main

import (
    "fmt"
    "io"
    "net/http"
    "net/url"
    "sync"
    "time"
)

// ProxyRotator manages a list of proxies and provides a round-robin selection.
type ProxyRotator struct {
    proxies []*url.URL
    current int
    mu      sync.Mutex
}

// NewProxyRotator creates a new ProxyRotator from a slice of proxy URLs.
func NewProxyRotator(proxyStrings []string) (*ProxyRotator, error) {
    proxies := make([]*url.URL, len(proxyStrings))
    for i, s := range proxyStrings {
        u, err := url.Parse(s)
        if err != nil {
            return nil, fmt.Errorf("invalid proxy URL '%s': %w", s, err)
        }
        proxies[i] = u
    }
    return &ProxyRotator{
        proxies: proxies,
        current: 0,
    }, nil
}

// GetProxy returns the next proxy in a round-robin fashion.
func (pr *ProxyRotator) GetProxy(_ *http.Request) (*url.URL, error) {
    if len(pr.proxies) == 0 {
        return nil, nil // No proxy
    }

    pr.mu.Lock()
    defer pr.mu.Unlock()

    proxy := pr.proxies[pr.current]
    pr.current = (pr.current + 1) % len(pr.proxies)
    return proxy, nil
}

func main() {
    proxyList := []string{
        "http://user1:[email protected]:8080",
        "http://user2:[email protected]:8080",
        "http://user3:[email protected]:8080",
    }

    rotator, err := NewProxyRotator(proxyList)
    if err != nil {
        fmt.Printf("Error creating proxy rotator: %v\n", err)
        return
    }

    client := &http.Client{
        Transport: &http.Transport{
            Proxy: rotator.GetProxy, // Assign the rotator's GetProxy method
        },
        Timeout: 15 * time.Second,
    }

    for i := 0; i < 5; i++ {
        resp, err := client.Get("http://httpbin.org/ip")
        if err != nil {
            fmt.Printf("Request %d error: %v\n", i+1, err)
            continue
        }
        defer resp.Body.Close()

        body, err := io.ReadAll(resp.Body)
        if err != nil {
            fmt.Printf("Request %d error reading body: %v\n", i+1, err)
            continue
        }
        fmt.Printf("Request %d IP: %s\n", i+1, body)
        time.Sleep(1 * time.Second) // Simulate some work
    }
}

Este exemplo implementa um rotacionador round-robin básico. Rotacionadores mais avançados podem:
* Monitorar a saúde dos proxies e remover os que falham.
* Implementar diferentes estratégias de rotação (por exemplo, ponderada, aleatória).
* Integrar-se a serviços externos de gerenciamento de proxies.

Tráfego HTTPS através de proxies

Quando um http.Client faz uma requisição https:// através de um proxy HTTP, o http.Transport executa um handshake pelo método CONNECT com o proxy. O cliente pede ao proxy que estabeleça um túnel TCP até o host e a porta de destino (normalmente 443). Uma vez estabelecido o túnel, o cliente faz o handshake TLS diretamente com o servidor de destino através do túnel do proxy. O próprio proxy não descriptografa o tráfego HTTPS (a menos que seja um proxy "man-in-the-middle", o que é um cenário diferente e exige configurações específicas de confiança).

Para requisições https://, a função Proxy deve retornar a URL do proxy normalmente. O net/http do Go trata o método CONNECT automaticamente.

Verificação TLS/SSL

Por padrão, os clientes Go fazem verificação estrita do certificado TLS. Se o certificado do servidor de destino não puder ser verificado (por exemplo, autoassinado, expirado ou de uma CA não confiável), a requisição falhará.

Em cenários específicos (por exemplo, testes com certificados autoassinados conhecidos em um ambiente controlado), você pode desativar a verificação de certificado usando InsecureSkipVerify em tls.Config.

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "net/http"
    "net/url"
    "time"
)

func main() {
    proxyStr := "http://your_proxy_ip:port"
    proxyURL, err := url.Parse(proxyStr)
    if err != nil {
        fmt.Printf("Error parsing proxy URL: %v\n", err)
        return
    }

    // Configure a custom Transport for TLS settings
    tr := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),
        TLSClientConfig: &tls.Config{
            // WARNING: InsecureSkipVerify should not be used in production environments.
            // It disables certificate chain and hostname verification.
            InsecureSkipVerify: true,
        },
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).DialContext,
        MaxIdleConns:        100,
        IdleConnTimeout:     90 * time.Second,
        TLSHandshakeTimeout: 10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }

    client := &http.Client{
        Transport: tr,
        Timeout: 15 * time.Second, // Overall request timeout
    }

    // Example target for HTTPS
    resp, err := client.Get("https://example.com")
    if err != nil {
        fmt.Printf("Error making HTTPS request with proxy: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response body: %v\n", err)
        return
    }
    fmt.Printf("Response status from https://example.com: %s\n", resp.Status)
    // fmt.Printf("Response body: %s\n", body) // Omitted for brevity
    _ = body
}

Comparação: proxies HTTP/HTTPS vs. SOCKS5

Característica Proxy HTTP/HTTPS Proxy SOCKS5
Camada do protocolo Camada de aplicação (Camada 7) Camada de sessão (Camada 5)
Tráfego suportado Principalmente requisições HTTP/HTTPS Qualquer tráfego TCP/UDP (HTTP, FTP, SMTP, DNS etc.)
Filtragem de tráfego Pode inspecionar cabeçalhos HTTP, URLs e conteúdo Em geral não inspeciona o conteúdo do tráfego
Autenticação HTTP Basic, Digest (o Go só suporta Basic na URL) Usuário/senha (método SOCKS5 AUTH)
Facilidade de uso (Go) Suporte nativo em net/http (http.ProxyURL) Requer o pacote golang.org/x/net/proxy
Desempenho Overhead potencialmente maior por analisar HTTP Em geral menor overhead, atua como um relay simples
Casos de uso Web scraping, interação com API, filtragem web Tunelamento de rede em geral, contornar firewalls

Boas práticas

  • Defina timeouts: sempre configure timeouts para http.Client e http.Transport (por exemplo, DialContext, TLSHandshakeTimeout) para evitar que as requisições fiquem penduradas indefinidamente, especialmente ao lidar com proxies instáveis.
  • Tratamento robusto de erros: os erros relacionados a proxy variam (por exemplo, net.OpError para problemas de conexão, io.EOF para desconexões inesperadas). Implemente tratamento de erros abrangente e lógica de retentativa.
  • Gerenciamento de proxies: em cenários dinâmicos, implemente um sistema robusto de gerenciamento de proxies que monitore a saúde dos proxies, faça a rotação de forma eficaz e lide bem com falhas.
  • Gerenciamento de recursos: garanta que resp.Body.Close() seja chamado com defer para liberar os recursos de rede.
  • Context para cancelamento: use context.Context com http.Request para permitir cancelamento de requisições e controle de timeout entre funções.
  • Evite InsecureSkipVerify: não use InsecureSkipVerify = true em ambientes de produção, a menos que você entenda plenamente as implicações de segurança e tenha controles compensatórios.
Atualizado: 03.03.2026
Voltar à categoria

Leia também

Experimente nossos proxies

20,000+ proxies em 100+ países do mundo

support_agent
GProxy Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.