Перейти до вмісту
Гайды 8 хв читання 34 переглядів

Використання проксі в Go (Golang)

Ознайомтеся з основами використання HTTP та SOCKS проксі в Go (Golang). Ц

Використання проксі в Go (Golang)

Використання проксі в Go передбачає налаштування http.Transport для http.Client за допомогою функції Proxy, зазвичай http.ProxyURL для статичних проксі або спеціальної функції для динамічного вибору проксі.

Навіщо використовувати проксі в Go?

Проксі слугують різним цілям у мережевій комунікації, особливо при виконанні HTTP-запитів з Go-додатків:

  • Анонімність: Маскування оригінальної IP-адреси клієнта.
  • Геотаргетинг: Доступ до контенту або послуг, обмежених певними географічними регіонами, шляхом маршрутизації запитів через проксі, розташовані в цих регіонах.
  • Обмеження швидкості запитів: Розподіл запитів між кількома IP-адресами, щоб уникнути перевищення лімітів швидкості, встановлених цільовими серверами.
  • Веб-скрейпінг: Сприяння великомасштабному збору даних шляхом ротації IP-адрес, обходу виявлення та керування обсягом запитів.
  • Безпека та фільтрація: Маршрутизація трафіку через корпоративні проксі для сканування безпеки, фільтрації контенту або контролю доступу.
  • Налагодження: Перехоплення та інспектування трафіку.

Налаштування HTTP-клієнта з проксі

Стандартна бібліотека Go net/http надає надійну підтримку конфігурацій проксі. Основний механізм передбачає зміну http.Transport, пов'язаного з http.Client.

Використання http.ProxyFromEnvironment

Найпростіший спосіб використання проксі — це використання змінних середовища. Функція Go http.ProxyFromEnvironment перевіряє змінні середовища HTTP_PROXY, HTTPS_PROXY та NO_PROXY.

  • HTTP_PROXY: Використовується для http:// запитів.
  • HTTPS_PROXY: Використовується для https:// запитів.
  • NO_PROXY: Список хостів, розділених комами, які повинні обходити проксі.
package main

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

func main() {
    // Встановлення змінних середовища (для демонстрації)
    os.Setenv("HTTP_PROXY", "http://your_proxy_ip:port")
    os.Setenv("HTTPS_PROXY", "http://your_proxy_ip:port") // Примітка: HTTPS_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("Помилка при виконанні запиту: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Помилка при читанні тіла відповіді: %v\n", err)
        return
    }
    fmt.Printf("Відповідь від httpbin.org/ip:\n%s\n", body)

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

Використання http.ProxyURL для статичних проксі

Для явної конфігурації проксі використовується http.ProxyURL. Ця функція приймає *url.URL, що представляє адресу проксі.

package main

import (
    "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("Помилка при парсингу 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("Помилка при виконанні запиту: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Помилка при читанні тіла відповіді: %v\n", err)
        return
    }
    fmt.Printf("Відповідь від httpbin.org/ip:\n%s\n", body)
}

Автентифікація проксі

Багато проксі вимагають автентифікації. Для HTTP/HTTPS проксі, що використовують базову автентифікацію, облікові дані можуть бути вбудовані безпосередньо в URL проксі:

package main

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

func main() {
    // Формат: "http://username:password@proxy_ip:port"
    proxyStr := "http://user:password@your_auth_proxy_ip:port" // Замініть на ваш автентифікований проксі
    proxyURL, err := url.Parse(proxyStr)
    if err != nil {
        fmt.Printf("Помилка при парсингу 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("Помилка при виконанні запиту з автентифікованим проксі: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Помилка при читанні тіла відповіді: %v\n", err)
        return
    }
    fmt.Printf("Відповідь від httpbin.org/ip через автентифікований проксі:\n%s\n", body)
}

Використання SOCKS5 проксі

Хоча net/http безпосередньо підтримує HTTP/HTTPS проксі, SOCKS5 проксі вимагають додаткового пакету: golang.org/x/net/proxy. SOCKS5 працює на нижчому рівні, ніж HTTP проксі, підтримуючи різні протоколи.

Щоб використовувати SOCKS5 проксі, вам потрібно створити Dialer за допомогою пакету proxy, а потім призначити його полю DialContext у http.Transport.

package main

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

    "golang.org/x/net/proxy" // Переконайтеся, що ви виконали 'go get golang.org/x/net/proxy'
)

func main() {
    socks5Proxy := "socks5://user:password@your_socks5_proxy_ip:port" // Замініть на ваш SOCKS5 проксі

    dialer, err := proxy.SOCKS5("tcp", socks5Proxy[len("socks5://"):], nil, proxy.Direct) // Базова автентифікація обробляється dialer'ом
    if err != nil {
        fmt.Printf("Помилка при створенні SOCKS5 dialer: %v\n", err)
        return
    }

    // Для автентифікованого SOCKS5, функція proxy.SOCKS5 обробляє його, якщо URL містить облікові дані.
    // Якщо функція proxy.SOCKS5 не парсить облікові дані безпосередньо, вам може знадобитися
    // витягти їх і передати структуру proxy.Auth. Приклад:
    // 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)
            },
            // За бажанням, встановіть TLSClientConfig для HTTPS через SOCKS5
            // TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // Використовуйте з обережністю
        },
        Timeout: 10 * time.Second,
    }

    resp, err := client.Get("http://httpbin.org/ip")
    if err != nil {
        fmt.Printf("Помилка при виконанні запиту з SOCKS5 проксі: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Помилка при читанні тіла відповіді: %v\n", err)
        return
    }
    fmt.Printf("Відповідь від httpbin.org/ip через SOCKS5 проксі:\n%s\n", body)
}

Динамічний вибір та ротація проксі

Для таких додатків, як веб-скрейпінг або великомасштабний збір даних, ротація проксі є важливою для уникнення блокування IP-адрес та керування обсягом запитів. Це вимагає спеціальної функції Proxy для http.Transport.

Поле Proxy у http.Transport очікує функцію з сигнатурою func(*http.Request) (*url.URL, error). Ця функція викликається перед кожним запитом, дозволяючи динамічний вибір проксі на основі властивостей запиту або стратегії ротації.

package main

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

// ProxyRotator керує списком проксі та забезпечує циклічний вибір.
type ProxyRotator struct {
    proxies []*url.URL
    current int
    mu      sync.Mutex
}

// NewProxyRotator створює новий ProxyRotator зі зрізу URL-адрес проксі.
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("недійсний URL проксі '%s': %w", s, err)
        }
        proxies[i] = u
    }
    return &ProxyRotator{
        proxies: proxies,
        current: 0,
    }, nil
}

// GetProxy повертає наступний проксі в циклічному порядку.
func (pr *ProxyRotator) GetProxy(_ *http.Request) (*url.URL, error) {
    if len(pr.proxies) == 0 {
        return nil, nil // Без проксі
    }

    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("Помилка при створенні ротатора проксі: %v\n", err)
        return
    }

    client := &http.Client{
        Transport: &http.Transport{
            Proxy: rotator.GetProxy, // Призначити метод GetProxy ротатора
        },
        Timeout: 15 * time.Second,
    }

    for i := 0; i < 5; i++ {
        resp, err := client.Get("http://httpbin.org/ip")
        if err != nil {
            fmt.Printf("Помилка запиту %d: %v\n", i+1, err)
            continue
        }
        defer resp.Body.Close()

        body, err := io.ReadAll(resp.Body)
        if err != nil {
            fmt.Printf("Помилка читання тіла запиту %d: %v\n", i+1, err)
            continue
        }
        fmt.Printf("IP запиту %d: %s\n", i+1, body)
        time.Sleep(1 * time.Second) // Імітація деякої роботи
    }
}

Цей приклад реалізує базовий циклічний ротатор. Більш просунуті ротатори можуть:
* Відстежувати стан проксі та видаляти несправні проксі.
* Реалізовувати різні стратегії ротації (наприклад, зважені, випадкові).
* Інтегруватися із зовнішніми службами керування проксі.

HTTPS-трафік через проксі

Коли http.Client виконує https:// запит через HTTP-проксі, http.Transport виконує рукостискання методом CONNECT з проксі. Клієнт просить проксі встановити TCP-тунель до цільового хоста та порту (зазвичай 443). Після встановлення тунелю клієнт виконує TLS-рукостискання безпосередньо з цільовим сервером через проксі-тунель. Сам проксі не розшифровує HTTPS-трафік (якщо це не проксі "людина посередині", що є іншим сценарієм, що вимагає спеціальних конфігурацій довіри).

Для https:// запитів функція Proxy повинна повертати URL проксі як зазвичай. net/http Go автоматично обробляє метод CONNECT.

Перевірка TLS/SSL

За замовчуванням клієнти Go виконують строгу перевірку TLS-сертифікатів. Якщо сертифікат цільового сервера не може бути перевірений (наприклад, самопідписаний, прострочений або неперевірений CA), запит завершиться помилкою.

У певних сценаріях (наприклад, тестування з відомими самопідписаними сертифікатами в контрольованому середовищі) ви можете вимкнути перевірку сертифікатів за допомогою InsecureSkipVerify у 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("Помилка при парсингу URL проксі: %v\n", err)
        return
    }

    // Налаштування спеціального Transport для параметрів TLS
    tr := &http.Transport{
        Proxy: http.ProxyURL(proxyURL),
        TLSClientConfig: &tls.Config{
            // ПОПЕРЕДЖЕННЯ: InsecureSkipVerify не слід використовувати в виробничих середовищах.
            // Він вимикає перевірку ланцюжка сертифікатів та імені хоста.
            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, // Загальний тайм-аут запиту
    }

    // Приклад цілі для HTTPS
    resp, err := client.Get("https://example.com")
    if err != nil {
        fmt.Printf("Помилка при виконанні HTTPS-запиту з проксі: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Помилка при читанні тіла відповіді: %v\n", err)
        return
    }
    fmt.Printf("Статус відповіді від https://example.com: %s\n", resp.Status)
    // fmt.Printf("Тіло відповіді: %s\n", body) // Опущено для стислості
    _ = body
}

Порівняння: HTTP/HTTPS проти SOCKS5 проксі

Функція HTTP/HTTPS Проксі SOCKS5 Проксі
Рівень протоколу Прикладний рівень (Рівень 7) Сесійний рівень (Рівень 5)
Підтримуваний трафік Переважно HTTP/HTTPS запити Будь-який TCP/UDP трафік (HTTP, FTP, SMTP, DNS тощо)
Фільтрація трафіку Може перевіряти HTTP-заголовки, URL-адреси та вміст Зазвичай не перевіряє вміст трафіку
Автентифікація HTTP Basic, Digest (Go підтримує лише Basic в URL) Ім'я користувача/Пароль (метод SOCKS5 AUTH)
Простота використання (Go) Вбудована підтримка в net/http (http.ProxyURL) Вимагає пакету golang.org/x/net/proxy
Продуктивність Потенційно вищі накладні витрати через парсинг HTTP Зазвичай нижчі накладні витрати, діє як простий ретранслятор
Випадки використання Веб-скрейпінг, взаємодія з API, веб-фільтрація Загальне тунелювання мережі, обхід брандмауерів

Найкращі практики

  • Встановлюйте тайм-аути: Завжди налаштовуйте тайм-аути для http.Client та http.Transport (наприклад, DialContext, TLSHandshakeTimeout), щоб запобігти зависанню запитів на невизначений термін, особливо при роботі з ненадійними проксі.
  • Надійна обробка помилок: Помилки, пов'язані з проксі, можуть відрізнятися (наприклад, net.OpError для проблем з підключенням, io.EOF для несподіваних відключень). Реалізуйте комплексну обробку помилок та логіку повторних спроб.
  • Керування проксі: Для динамічних сценаріїв реалізуйте надійну систему керування проксі, яка відстежує стан проксі, ефективно ротує проксі та витончено обробляє збої.
  • Керування ресурсами: Переконайтеся, що resp.Body.Close() викликається за допомогою defer для звільнення мережевих ресурсів.
  • Контекст для скасування: Використовуйте context.Context з http.Request, щоб увімкнути скасування запитів та керування тайм-аутами між функціями.
  • Уникайте InsecureSkipVerify: Не використовуйте InsecureSkipVerify = true у виробничих середовищах, якщо ви повністю не розумієте наслідків для безпеки та не маєте компенсуючих засобів контролю.
Оновлено: 03.03.2026
Назад до категорії

Читайте також

Гайды 1 хв

Налаштування проксі в Cypress для E2E тестування

Налаштування проксі в Cypress: змінні HTTP_PROXY, cy-proxy-middleware та тестування геозалежного контенту.

Гайды 1 хв

Як автоматизувати купівлю проксі через API

Автоматизація купівлі та управління проксі через API провайдерів: інтеграція, моніторинг використання та автопоновлення.

Гайды 1 хв

Створення інформаційної панелі моніторингу проксі в Grafana

Покрокове створення інформаційної панелі для моніторингу проксі в Grafana: метрики,

Гайды 1 хв

Як тестувати проксі перед покупкою

Чек-лист тестування проксі перед покупкою: швидкість, стабільність, анонімність, гео та сумісність з ціллю

Гайды 1 хв

Як налаштувати липкі сесії через проксі

Липкі сесії: підтримка однієї IP-адреси протягом усієї сесії, налаштовуються через провайдера та самостійно.

Гайды 1 хв

Використання проксі з Camoufox

Camoufox — це модифікований Firefox для обходу антиботів. Налаштування проксі, відбиток та режим невидимості.

Спробуйте наші проксі

20,000+ проксі в 100+ країнах світу

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