Как зарегистрировать тело запроса (через промежуточное ПО) без буферизации? - PullRequest
0 голосов
/ 12 января 2020

Предположим, у меня был этот простой сервер (для краткости обработка ошибок опущена):

func main() {
    http.HandleFunc("/", HelloServer)
    http.ListenAndServe(":8080", nil)
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
    b, _ := ioutil.ReadAll(r.Body)
    fmt.Fprintf(w, "The request is: %s", string(b))
}

Мне нужно добавить простое промежуточное ПО, которое читает тело запроса и регистрирует его. У меня уже есть это рабочее решение:

func requestLogger(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        pr, pw := io.Pipe()
        tee := io.TeeReader(r.Body, pw)
        r.Body = pr
        go func() {
            body, _ := ioutil.ReadAll(tee)
            defer pw.Close()
            log.Printf("This is the logged request: %s", string(body))
        }()
        next(w, r)
    }
}

Я пришел к этому решению интуитивно методом проб и ошибок, поэтому я не уверен, будет ли оно работать во всех случаях. Вот мои вопросы относительно моего собственного решения:

  1. Почему я должен вручную закрывать Pipe? Не ioutil.ReadAll() закрывает его, когда встречает EOF на r .Body.
  2. Почему это не блокировка? Имеется циклическая ссылка, потому что TeeReader читает из того же источника (r.Body), в который он пишет через канал (r.Body = пр). Согласно документации, запись в блок PipeWriter выполняется до тех пор, пока он не выполнит одно или несколько операций чтения, а в случае TeeReader запись должна быть завершена до завершения операции чтения.

1 Ответ

1 голос
/ 12 января 2020

Разве ioutil.ReadAll () не закрывает его при обнаружении EOF?


Пакет ioutil

fun c ReadAll

func ReadAll(r io.Reader) ([]byte, error)

ReadAll читает от r до ошибки или EOF и возвращает прочитанные данные.


То есть не документированное поведение. Кроме того, io.Reader не является io.ReadCloser.

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