Подтвердить что ты не робот

Чтение тела http.Request без изменения состояния запроса?

У меня есть тип, реализующий интерфейс http.Handler, где в своем методе ServeHTTP проверяются входящие HTTP-запросы, предпринимаются некоторые действия, а затем запросы пересылаются обратному обработчику прокси (httputil.NewSingleHostReverseProxy).

Это работает отлично, пока я только проверяю основные свойства запроса, такие как URL или заголовки.

Когда я хочу проверить тело входящего запроса POST, например. вызывая req.ParseForm(), а затем используя свойство req.Form, я запускаю ошибку после отправки запроса на обратный прокси:

http: proxy error: http: Request.ContentLength=687 with Body length 0

Я предполагаю, что это происходит, потому что просмотр тела HTTP-запроса приводит к истощению потока req.Body.Reader, что означает, что обработчик прокси не может быть снова прочитан.

Я играл с такими вещами, как io.Copy() и bufio.Peek(), но я ничего не понимаю.

Есть ли способ заглянуть в тело запроса HTTP (и использовать встроенный синтаксический анализ req.ParseForm и т.д.), оставив исходный объект запроса в его исходном состоянии, чтобы его можно было передать на обратную прокси-сервер?

4b9b3361

Ответ 1

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

doStuff(r.Body) // r is an http.Request

Мы могли бы сделать:

buf, _ := ioutil.ReadAll(r.Body)
rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf))
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))

doStuff(rdr1)
r.Body = rdr2 // OK since rdr2 implements the io.ReadCloser interface

// Now the program can continue oblivious to the fact that
// r.Body was ever touched.

Обратите внимание, что *bytes.Buffer не имеет метода Close() error, поэтому он не реализует интерфейс io.ReadCloser. Таким образом, мы должны обернуть наши значения *bytes.Buffer при вызовах ioutil.NopCloser.