Как в Go реализовать прокси-сервер и какие типы прокси существуют?

Ответ

Прокси-сервер — это посредник между клиентом и сервером. Основные типы прокси и их реализация в Go:

1. Reverse Proxy (Обратный прокси)

Назначение: Принимает запросы от клиентов и перенаправляет их на один или несколько бэкенд-серверов. Используется для балансировки нагрузки, SSL-терминации, кэширования и сокрытия внутренней архитектуры.

Реализация в Go: Очень проста благодаря пакету net/http/httputil.

import (
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    // URL бэкенд-сервера, на который будут проксироваться запросы
    target, err := url.Parse("http://localhost:8081")
    if err != nil {
        log.Fatal(err)
    }

    // Создаем reverse proxy
    proxy := httputil.NewSingleHostReverseProxy(target)

    // Запускаем HTTP-сервер, который будет использовать прокси как обработчик
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Proxying request for: %s", r.URL.Path)
        proxy.ServeHTTP(w, r)
    })

    log.Println("Reverse proxy server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

2. Forward Proxy (Прямой прокси)

Назначение: Принимает запросы от клиентов из внутренней сети и перенаправляет их во внешнюю сеть (интернет). Используется для обхода блокировок, фильтрации трафика, анонимизации.

Реализация в Go: Можно написать вручную, реализовав интерфейс http.Handler. Приведенный ниже пример — упрощенный и не обрабатывает HTTPS-трафик (метод CONNECT).

func handleHTTP(w http.ResponseWriter, r *http.Request) {
    // Создаем новый запрос на основе оригинального
    proxyReq, err := http.NewRequest(r.Method, r.URL.String(), r.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    proxyReq.Header = r.Header

    // Выполняем запрос
    client := &http.Client{}
    resp, err := client.Do(proxyReq)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadGateway)
        return
    }
    defer resp.Body.Close()

    // Копируем заголовки и тело ответа клиенту
    for key, values := range resp.Header {
        for _, value := range values {
            w.Header().Add(key, value)
        }
    }
    w.WriteHeader(resp.StatusCode)
    io.Copy(w, resp.Body)
}

Готовые решения

Помимо самостоятельной реализации, в экосистеме Go популярны готовые прокси-серверы, написанные на Go:

  • Traefik: Современный reverse proxy и балансировщик нагрузки, который легко интегрируется с Docker и Kubernetes.
  • Caddy: Веб-сервер с автоматической поддержкой HTTPS, который также может работать как мощный reverse proxy.
  • Envoy / Nginx: Хотя они написаны не на Go, для них существуют Go-библиотеки и SDK для управления и расширения их функциональности.

Ответ 18+ 🔞

А, прокси-серверы, говоришь? Ну это ж как бабка у подъезда, блядь, которая всем передаёт сплетни, но сама нихуя не понимает, о чём речь. Сидит, сука, посредником между тобой и интернетом, а сама думает: "Чё они там опять не поделили?"

Reverse Proxy (Обратный прокси) — это типа швейцар в дорогом отеле. Ты, лох, пришёл с улицы, а он тебя встречает, кивает, а сам думает: "Сейчас я этого пидораса на кухню отправлю, пусть там ему котлету подогреют". Балансирует нагрузку, SSL там всякий терминирует — в общем, делает вид, что он главный, а сам просто перенаправляет запросы куда надо.

В Go это, блядь, проще пареной репы, потому что есть пакет net/http/httputil. Смотри, как это выглядит, ёпта:

import (
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    // Куда будем проксировать — типа адрес кухни, где котлеты готовят
    target, err := url.Parse("http://localhost:8081")
    if err != nil {
        log.Fatal(err)
    }

    // Создаём этого самого швейцара-прокси
    proxy := httputil.NewSingleHostReverseProxy(target)

    // Вешаем его на все запросы
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Proxying request for: %s", r.URL.Path)
        proxy.ServeHTTP(w, r)
    })

    log.Println("Reverse proxy server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Вот и весь, блядь, цирк. Запустил — и он уже работает, как та самая мартышлюшка с переключателем.

Forward Proxy (Прямой прокси) — это уже не швейцар, а скорее мудак-посыльный из офиса, который бегает за сигаретами для всех сотрудников. Ты из своей локальной сети просишь: "Сходи на pornhub.com", а он такой: "Ага, щас". И идёт, сука, в интернет, делает вид, что это он сам захотел посмотреть, а не ты.

Реализовать его чуть сложнее, потому что нужно руками запросы переписывать. Вот упрощённый пример, который HTTPS (CONNECT метод) не обрабатывает — так, для затравки:

func handleHTTP(w http.ResponseWriter, r *http.Request) {
    // Делаем копию запроса, как будто это мы сами хотим
    proxyReq, err := http.NewRequest(r.Method, r.URL.String(), r.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    proxyReq.Header = r.Header

    // Выполняем его, как будто мы честные люди
    client := &http.Client{}
    resp, err := client.Do(proxyReq)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadGateway)
        return
    }
    defer resp.Body.Close()

    // А теперь всё, что получили, отдаём обратно тому, кто просил
    for key, values := range resp.Header {
        for _, value := range values {
            w.Header().Add(key, value)
        }
    }
    w.WriteHeader(resp.StatusCode)
    io.Copy(w, resp.Body)
}

Ну и, конечно, если тебе лень эту всю хуйню самому писать, есть готовые решения, которые уже всё за тебя сделали, блядь.

  • Traefik — это такой навороченный швейцар с планшетом, который ещё и в Docker'е разбирается. Модно, молодёжно, ёпта.
  • Caddy — это как швейцар, который сам себе SSL-сертификаты выписывает, пока ты спишь. Удобно, бля, до охуения.
  • Envoy / Nginx — это уже монстры, старые, бородатые, на C++ написаны, но для них есть Go-библиотеки, чтобы ты мог ими управлять, не пачкая руки об их исходники.

Вот так вот, коротко и без лишней воды. А то некоторые так расписывают, будто это квантовая физика, а на деле — обычный передаточный механизм, в рот меня чих-пых!