http.Request.Clone () не является глубоким клоном? - PullRequest
0 голосов
/ 26 мая 2020

Я хочу получить запрос и использовать ParseForm для проверки некоторых данных, затем отправить тот же самый на прокси, купить, если я это сделаю, у нас есть проблема

журнал ошибок, как это

2020/05/26 15:34:47 http: ошибка прокси: net / http: транспортное соединение HTTP / 1.x разорвано: http: ContentLength = 32 с длиной тела 0

поэтому я, наконец, понял это, ParseForm () хорошо закрывает Request .body

, и это рабочий прокси-код

    url, _ := url.Parse(config.GetGameHost())

    proxy := httputil.NewSingleHostReverseProxy(url)
    r.URL.Host = url.Host
    r.URL.Scheme = url.Scheme
    r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
    r.Host = url.Host
    proxy.ServeHTTP(w, r)

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

nr := r.Clone(r.Context())
nr.ParseForm()

url, _ := url.Parse(config.GetGameHost())

proxy := httputil.NewSingleHostReverseProxy(url)

r.URL.Host = url.Host
r.URL.Scheme = url.Scheme
r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
r.Host = url.Host

proxy.ServeHTTP(w, r)

, и журнал ошибок снова отображается

2020/05/26 15:49:29 http: proxy ошибка: net / http: транспортное соединение HTTP / 1.x разорвано: http: ContentLength = 32 с длиной тела 0

является ли Clone () не глубоким клоном или я ошибаюсь?

------------ эта работа ------------

body, err := ioutil.ReadAll(r.Body)
if err != nil {
    // ...
}
url, _ := url.Parse(config.GetGameHost())

r2 := r.Clone(r.Context())

r.Body = ioutil.NopCloser(bytes.NewReader(body))
r2.Body = ioutil.NopCloser(bytes.NewReader(body))

r.ParseForm()

proxy := httputil.NewSingleHostReverseProxy(url)
proxy.ServeHTTP(w, r2)

1 Ответ

3 голосов
/ 26 мая 2020

http.Request.Body можно прочитать только один раз, необходимо скопировать новое тело.

body,err := ioutil.ReadAll(r)
if err != nil {
    // ...
}
r2 := r.Clone(r.Context())
// clone body
r.Body = ioutil.NopCloser(bytes.NewReader(body))
r2.Body = ioutil.NopCloser(bytes.NewReader(body))

// parse r1, proxy r2
r.ParseForm()
proxy.ServerHTTP(w, r2)

По умолчанию для объекта тела используется многослойная инкапсуляция net .Conn. Каждый раз, когда он использует интерфейс io.Reader для чтения 4 Кбайт, экономя использование памяти, он обычно используется при чтении из сети.

Следовательно, тело может быть прочитано из сети только один раз. Если вы хотите, чтобы объект тела читался неоднократно, вы должны прочитать его все, сохранить и использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...