Golang read request body

Piszę własne logginMiddleware. Zasadniczo, muszę zapisać treść prośby i odpowiedzi. Problem, który napotkałem jest to, że kiedy czytam ciało, staje się puste i nie mogę przeczytać go dwa razy. Rozumiem, że dzieje się tak, ponieważ jest typu ReadCloser. Czy istnieje sposób na przewinięcie ciała do początku?

Author: Rustam Ibragimov, 2017-03-25

2 answers

Kontrola i wyśmiewanie organu wnioskującego

Kiedy po raz pierwszy przeczytasz ciało, musisz je przechowywać, aby po jego zakończeniu można było ustawić nowy io.ReadCloser jako organ żądania zbudowany z oryginalnych danych. Więc po przejściu w łańcuchu, następny opiekun może odczytać to samo ciało.

Jedną z opcji jest odczytanie całego ciała za pomocą ioutil.ReadAll(), co daje Ci ciało jako kawałek bajtu.

Możesz użyć bytes.NewBuffer() aby uzyskać io.Reader z kawałka bajtów.

Ostatnim brakującym elementem jest zrobienie io.Reader io.ReadCloser, ponieważ bytes.Buffer nie ma metody Close(). W tym celu możesz użyć ioutil.NopCloser() która zawija io.Reader i zwraca io.ReadCloser, której dodana metoda Close() będzie no-op (nie robi nic).

Zauważ, że możesz nawet zmodyfikować zawartość plasterka bajtów, którego używasz do utworzenia" nowego " ciała. Masz nad tym pełną kontrolę.

należy jednak zachować ostrożność, ponieważ mogą istnieć inne pola HTTP, takie jak content-długość i sumy kontrolne, które mogą stać się nieważne, jeśli zmodyfikujesz tylko dane. Jeśli kolejne manipulatory sprawdzają te, będziesz musiał je również zmodyfikować!

Kontrola / modyfikacja organu odpowiedzi

Jeśli chcesz również przeczytać treść odpowiedzi, musisz zawinąć http.ResponseWriter dostajesz i podajesz opakowanie na łańcuchu. Wrapper ten może buforować wysyłane dane, które można sprawdzić albo po, w locie (jak kolejne programy obsługi piszą do it).

Oto prosty wrapper ResponseWriter, który po prostu buforuje dane, więc będzie dostępny po następnym zakończeniu obsługi:

type MyResponseWriter struct {
    http.ResponseWriter
    buf *bytes.Buffer
}

func (mrw *MyResponseWriter) Write(p []byte) (int, error) {
    return mrw.buf.Write(p)
}

Zauważ, że MyResponseWriter.Write() po prostu zapisuje dane do bufora. Możesz również sprawdzić go w locie (w metodzie Write()) i natychmiast zapisać dane do owiniętego / osadzonego ResponseWriter. Możesz nawet modyfikować dane. Masz pełną kontrolę.

należy jednak ponownie zachować ostrożność, ponieważ kolejne manipulatory mogą również wysyłać HTTP nagłówki odpowiedzi związane z danymi odpowiedzi - takimi jak długość lub sumy kontrolne-które również mogą stać się nieważne, jeśli zmienisz dane odpowiedzi.

Pełny przykład

Po złożeniu elementów do kupy, oto pełny przykład pracy:]}
func loginmw(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
            log.Printf("Error reading body: %v", err)
            http.Error(w, "can't read body", http.StatusBadRequest)
            return
        }

        // Work / inspect body. You may even modify it!

        // And now set a new body, which will simulate the same data we read:
        r.Body = ioutil.NopCloser(bytes.NewBuffer(body))

        // Create a response wrapper:
        mrw := &MyResponseWriter{
            ResponseWriter: w,
            buf:            &bytes.Buffer{},
        }

        // Call next handler, passing the response wrapper:
        handler.ServeHTTP(mrw, r)

        // Now inspect response, and finally send it out:
        // (You can also modify it before sending it out!)
        if _, err := io.Copy(w, mrw.buf); err != nil {
            log.Printf("Failed to send out response: %v", err)
        }
    })
}
 49
Author: icza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-20 16:28:33

Mógłbym użyć GetBody z pakietu Request.

Spójrz na ten komentarz w kodzie źródłowym z request.przejdź do net / http

GetBody definiuje opcjonalny func, aby zwrócić nową kopię Ciało. Jest on używany do żądań klientów, gdy przekierowanie wymaga czytanie ciała więcej niż raz. Korzystanie z GetBody still wymaga ustawienia ciała. Dla żądań serwera jest on nieużywany."

GetBody func() (io.ReadCloser, error)

W ten sposób można uzyskać żądanie ciała bez make him pusty.

Próbka:

getBody := request.GetBody copyBody, _ := getBody() http.DefaultClient.Do(request)

 0
Author: Yuri Giovani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-29 14:22:26