Прокси выбирает transport HTTP-клиента Go. Прежде чем менять стандартный transport, клонируйте его, чтобы другие пользователи клиента по умолчанию сохранили свои маршруты.

package main

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

func main() {
    proxyURL, err := url.Parse("http://203.0.113.10:8080")
    if err != nil {
        log.Fatal(err)
    }

    transport := http.DefaultTransport.(*http.Transport).Clone()
    transport.Proxy = http.ProxyURL(proxyURL)
    defer transport.CloseIdleConnections()

    client := &http.Client{
        Transport: transport,
        Timeout:   15 * time.Second,
    }

    response, err := client.Get("https://example.com/")
    if err != nil {
        log.Fatal(err)
    }
    defer response.Body.Close()

    fmt.Println(response.StatusCode)
    if _, err := io.Copy(io.Discard, response.Body); err != nil {
        log.Fatal(err)
    }
}

Адрес — заполнитель из документации. Замените его настоящими IP и портом HTTP-прокси, например кандидатом из списка HTTP-прокси. Пример использует только стандартную библиотеку Go; для этого запроса через HTTP-прокси не нужны ни пакет SOCKS, ни переменная окружения для всего процесса.

Почему не менять DefaultTransport напрямую?

Стандартный transport используется совместно. Его изменение может повлиять на код, который не собирался использовать ваш прокси, а изменение во время запросов создаёт устранимые проблемы конкурентного доступа. Отдельный transport делает маршрут частью конфигурации именно этого клиента.

http.ProxyURL возвращает селектор, который всегда выбирает переданный URL. Это отличается от стандартного селектора окружения, учитывающего прокси-переменные и правила обхода. Если вы хотите проверить одну конкретную запись HTTP-списка, явный селектор убирает этот источник неоднозначности.

Закройте ответ и используйте клиент повторно

Пример дочитывает тело ответа и закрывает его. Чтение до конца помогает transport повторно использовать соединение, когда это возможно. Если программа делает несколько запросов через один прокси, сохраняйте клиент и transport вместо создания новой пары для каждого запроса.

Тайм-аут клиента ограничивает не только открытие сокета, но и жизненный цикл запроса, включая чтение тела ответа. Ошибки чтения нужно обрабатывать и после возврата Get. Статус вроде 403 — не ошибка transport Go, поэтому проверяйте StatusCode отдельно от err.

Похожие статьи