Golang ReverseProxy на хост

Я пытаюсь реализовать обратный прокси-сервер в Go, который проксирует трафик на разные хосты на основе некоторого клиента, встроенного в URL-адрес. Реализация выглядит так:

type Offloader struct {
    tenantHostMap   map[string]string                   // Map a tenant to its host:port
    tenantProxyMap  map[string](*httputil.ReverseProxy) // Map a tenant to its reverse proxy
}

func (o *Offloader) OnCreate() {

    // Tenants Map
    o.tenantHostMap = make(map[string]string)
    o.tenantProxyMap = make(map[string]*httputil.ReverseProxy)
    o.PopulateTenantHostMap()

    // Rx
    http.HandleFunc("/", o.ServeHTTP)
    go http.ListenAndServe(":5555", nil)

}

// ServeHTTP is the callback that is called each time a Http Request is received.
func (o *Offloader) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    incomingUrl := req.URL.RequestURI()
    tenant := o.GetTenantFromUrl(incomingUrl)

    if proxy, ok := o.tenantProxyMap[tenant]; ok {
        proxy.ServeHTTP(w, req)
    }

    if remoteHostAddr, ok := o.tenantHostMap[tenant]; ok {
        remoteUrl, err := url.Parse(fmt.Sprintf("http://%s", remoteHostAddr))
        if err != nil {
            return
        }
        proxy := httputil.NewSingleHostReverseProxy(remoteUrl)
        o.tenantProxyMap[tenant] = proxy
        proxy.ServeHTTP(w, req) // non blocking

    } else {
        panic("Unknown Tenant")
    }
}

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

Когда я тестирую это, я получаю следующую ошибку:

2022/04/05 12:31:01 http: proxy error: readfrom tcp ****: http: invalid Read on closed Body
2022/04/05 12:31:01 http: superfluous response.WriteHeader call from net/http/httputil.(*ReverseProxy).defaultErrorHandler (reverseproxy.go:190)

Если я создаю новый обратный прокси-сервер для каждого запроса, а не повторно использую один и тот же прокси-сервер, ошибка не возникает.

Я думал, что прокси-сервер предназначен для каждого хоста, а не для каждого запроса (как следует из названия), поэтому мне интересно, почему возникает эта ошибка?

Я знаю, что мне нужно защитить карты от одновременного чтения/записи, однако в данный момент это не имеет значения.

Спасибо,

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
44
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что в сценарии, где предыдущий прокси уже существовал, вы сначала передаете ему запрос, а затем снова создаете прокси и снова передаете запрос. Другими словами: вы делаете два прокси-запроса для каждого входящего запроса, когда для этого арендатора уже заполнена карта tenantProxyMap.

Реализация ReverseProxy закрывает req.Body, поэтому во второй раз, когда вы передаете запрос прокси-серверу, он пытается прочитать уже закрытое тело. В результате вы видите ошибку http: invalid Read on closed Body.

Что вы должны попробовать, так это вернуться после проксирования запроса, например. добавив return:

if proxy, ok := o.tenantProxyMap[tenant]; ok {
    proxy.ServeHTTP(w, req)
    return
}

Не могу поверить, что мне платят за код, и я пропустил это. Спасибо

Bes Dollma 05.04.2022 13:53

Другие вопросы по теме