Ответ
Прокси-сервер — это посредник между клиентом и сервером. Основные типы прокси и их реализация в 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-библиотеки, чтобы ты мог ими управлять, не пачкая руки об их исходники.
Вот так вот, коротко и без лишней воды. А то некоторые так расписывают, будто это квантовая физика, а на деле — обычный передаточный механизм, в рот меня чих-пых!