Ir al contenido
GProxy
Registro
Гайды 9 min de lectura 35 vistas

Uso de Proxies en Go (Golang)

Explora los fundamentos del uso de proxies HTTP y SOCKS en Go (Golang). Esta guía cubre la configuración

Uso de Proxies en Go (Golang)

El uso de proxies en Go implica configurar el http.Transport de un http.Client con una función Proxy, típicamente http.ProxyURL para proxies estáticos o una función personalizada para la selección dinámica de proxies.

¿Por qué usar Proxies en Go?

Los proxies cumplen varios propósitos en la comunicación de red, particularmente al realizar solicitudes HTTP desde aplicaciones Go:

  • Anonimato: Enmascarar la dirección IP original del cliente.
  • Geolocalización: Acceder a contenido o servicios restringidos a regiones geográficas específicas enrutando las solicitudes a través de proxies ubicados en esas regiones.
  • Limitación de Tasa: Distribuir solicitudes entre múltiples direcciones IP para evitar alcanzar los límites de tasa impuestos por los servidores de destino.
  • Web Scraping: Facilitar la recopilación de datos a gran escala rotando direcciones IP, eludiendo la detección y gestionando el volumen de solicitudes.
  • Seguridad y Filtrado: Enrutar el tráfico a través de proxies corporativos para escaneo de seguridad, filtrado de contenido o control de acceso.
  • Depuración: Interceptar e inspeccionar el tráfico.

Configuración de un Cliente HTTP con un Proxy

La biblioteca estándar de Go, el paquete net/http, proporciona un soporte robusto para las configuraciones de proxy. El mecanismo principal implica modificar el http.Transport asociado con un http.Client.

Uso de http.ProxyFromEnvironment

La forma más sencilla de usar un proxy es aprovechar las variables de entorno. La función http.ProxyFromEnvironment de Go busca las variables de entorno HTTP_PROXY, HTTPS_PROXY y NO_PROXY.

  • HTTP_PROXY: Se utiliza para solicitudes http://.
  • HTTPS_PROXY: Se utiliza para solicitudes https://.
  • NO_PROXY: Una lista de nombres de host separados por comas que deben omitir el proxy.
package main

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

func main() {
    // Establecer variables de entorno (para demostración)
    os.Setenv("HTTP_PROXY", "http://your_proxy_ip:port")
    os.Setenv("HTTPS_PROXY", "http://your_proxy_ip:port") // Nota: HTTPS_PROXY puede ser un proxy HTTP
    // 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")
}

Uso de http.ProxyURL para Proxies Estáticos

Para una configuración explícita del proxy, se utiliza http.ProxyURL. Esta función toma un *url.URL que representa la dirección del proxy.

package main

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

func main() {
    proxyStr := "http://your_proxy_ip:port" // Reemplazar con la dirección de tu 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: %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)
}

Autenticación de Proxy

Muchos proxies requieren autenticación. Para proxies HTTP/HTTPS que usan Autenticación Básica, las credenciales pueden incrustarse directamente en la URL del proxy:

package main

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

func main() {
    // Formato: "http://username:password@proxy_ip:port"
    proxyStr := "http://user:password@your_auth_proxy_ip:port" // Reemplazar con tu proxy autenticado
    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)
}

Uso de Proxies SOCKS5

Aunque net/http soporta directamente proxies HTTP/HTTPS, los proxies SOCKS5 requieren un paquete adicional: golang.org/x/net/proxy. SOCKS5 opera a un nivel inferior que los proxies HTTP, soportando varios protocolos.

Para usar un proxy SOCKS5, necesitas crear un Dialer usando el paquete proxy y luego asignarlo al campo DialContext de http.Transport.

package main

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

    "golang.org/x/net/proxy" // Asegúrate de 'go get golang.org/x/net/proxy'
)

func main() {
    socks5Proxy := "socks5://user:password@your_socks5_proxy_ip:port" // Reemplazar con tu proxy SOCKS5

    dialer, err := proxy.SOCKS5("tcp", socks5Proxy[len("socks5://"):], nil, proxy.Direct) // La autenticación básica es manejada por el dialer
    if err != nil {
        fmt.Printf("Error creating SOCKS5 dialer: %v\n", err)
        return
    }

    // Para SOCKS5 autenticado, la función proxy.SOCKS5 lo maneja si la URL contiene credenciales.
    // Si la función proxy.SOCKS5 no analiza las credenciales directamente, es posible que necesites
    // extraerlas y pasar una estructura proxy.Auth. Ejemplo:
    // 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)
            },
            // Opcionalmente, configurar TLSClientConfig para HTTPS sobre SOCKS5
            // TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // Usar con precaución
        },
        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)
}

Selección y Rotación Dinámica de Proxies

Para aplicaciones como el web scraping o la recopilación de datos a gran escala, la rotación de proxies es esencial para evitar bloqueos de IP y gestionar el volumen de solicitudes. Esto requiere una función Proxy personalizada para http.Transport.

El campo Proxy de http.Transport espera una función con la firma func(*http.Request) (*url.URL, error). Esta función se llama antes de cada solicitud, permitiendo la selección dinámica de proxies basada en las propiedades de la solicitud o en una estrategia de rotación.

package main

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

// ProxyRotator gestiona una lista de proxies y proporciona una selección round-robin.
type ProxyRotator struct {
    proxies []*url.URL
    current int
    mu      sync.Mutex
}

// NewProxyRotator crea un nuevo ProxyRotator a partir de un slice de URLs de proxy.
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 devuelve el siguiente proxy de forma round-robin.
func (pr *ProxyRotator) GetProxy(_ *http.Request) (*url.URL, error) {
    if len(pr.proxies) == 0 {
        return nil, nil // Sin 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:pass1@proxy1.example.com:8080",
        "http://user2:pass2@proxy2.example.com:8080",
        "http://user3:pass3@proxy3.example.com: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, // Asignar el método GetProxy del rotador
        },
        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) // Simular algo de trabajo
    }
}

Este ejemplo implementa un rotador round-robin básico. Los rotadores más avanzados podrían:
* Rastrear la salud del proxy y eliminar los proxies que fallan.
* Implementar diferentes estrategias de rotación (por ejemplo, ponderada, aleatoria).
* Integrarse con servicios externos de gestión de proxies.

Tráfico HTTPS a Través de Proxies

Cuando un http.Client realiza una solicitud https:// a través de un proxy HTTP, el http.Transport realiza un handshake con el proxy utilizando el método CONNECT. El cliente le pide al proxy que establezca un túnel TCP al host y puerto de destino (típicamente 443). Una vez que el túnel está establecido, el cliente realiza el handshake TLS directamente con el servidor de destino a través del túnel del proxy. El proxy en sí no descifra el tráfico HTTPS (a menos que sea un proxy "man-in-the-middle", que es un escenario diferente que requiere configuraciones de confianza específicas).

Para las solicitudes https://, la función Proxy debe devolver la URL del proxy como de costumbre. net/http de Go maneja el método CONNECT automáticamente.

Verificación TLS/SSL

Por defecto, los clientes de Go realizan una verificación estricta del certificado TLS. Si el certificado del servidor de destino no puede ser verificado (por ejemplo, autofirmado, caducado o CA no confiable), la solicitud fallará.

En escenarios específicos (por ejemplo, pruebas con certificados autofirmados conocidos en un entorno controlado), podrías deshabilitar la verificación de certificados usando InsecureSkipVerify en tls.Config.

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "net"
    "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
    }

    // Configurar un Transport personalizado para ajustes TLS
    tr := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),
        TLSClientConfig: &tls.Config{
            // ADVERTENCIA: InsecureSkipVerify no debe usarse en entornos de producción.
            // Deshabilita la cadena de certificados y la verificación de nombre de host.
            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, // Tiempo de espera general de la solicitud
    }

    // Ejemplo de destino para 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) // Omitido por brevedad
    _ = body
}

Comparación: Proxies HTTP/HTTPS vs. SOCKS5

Característica Proxy HTTP/HTTPS Proxy SOCKS5
Capa de Protocolo Capa de Aplicación (Capa 7) Capa de Sesión (Capa 5)
Tráfico Soportado Principalmente solicitudes HTTP/HTTPS Cualquier tráfico TCP/UDP (HTTP, FTP, SMTP, DNS, etc.)
Filtrado de Tráfico Puede inspeccionar encabezados HTTP, URLs y contenido Generalmente no inspecciona el contenido del tráfico
Autenticación HTTP Basic, Digest (Go solo soporta Basic en URL) Nombre de usuario/Contraseña (método SOCKS5 AUTH)
Facilidad de Uso (Go) Soporte nativo en net/http (http.ProxyURL) Requiere el paquete golang.org/x/net/proxy
Rendimiento Potencialmente mayor sobrecarga debido al análisis HTTP Generalmente menor sobrecarga, actúa como un simple relé
Casos de Uso Web scraping, interacción con API, filtrado web Túneles de red generales, eludir firewalls

Mejores Prácticas

  • Establecer Tiempos de Espera: Siempre configura tiempos de espera para http.Client y http.Transport (por ejemplo, DialContext, TLSHandshakeTimeout) para evitar que las solicitudes se queden colgadas indefinidamente, especialmente al tratar con proxies poco fiables.
  • Manejo Robusto de Errores: Los errores relacionados con proxies pueden variar (por ejemplo, net.OpError para problemas de conexión, io.EOF para desconexiones inesperadas). Implementa un manejo de errores completo y lógica de reintentos.
  • Gestión de Proxies: Para escenarios dinámicos, implementa un sistema robusto de gestión de proxies que monitoree la salud de los proxies, los rote de manera efectiva y maneje los fallos con gracia.
  • Gestión de Recursos: Asegúrate de que resp.Body.Close() se llame usando defer para liberar los recursos de red.
  • Contexto para Cancelación: Usa context.Context con http.Request para habilitar la cancelación de solicitudes y la gestión de tiempos de espera en todas las funciones.
  • Evitar InsecureSkipVerify: No uses InsecureSkipVerify = true en entornos de producción a menos que comprendas completamente las implicaciones de seguridad y tengas controles compensatorios.
Actualizado: 03.03.2026
Volver a la categoría

Pruebe nuestros proxies

20,000+ proxies en 100+ países del mundo

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