receive golang body http go server

http - golang - go request body



Cuerpo de solicitud de lectura de Golang (2)

Inspección y burla del cuerpo de solicitud

Cuando lees el cuerpo por primera vez, debes almacenarlo, así que una vez que hayas terminado con él, puedes establecer un nuevo io.ReadCloser como el cuerpo de la solicitud construido a partir de los datos originales. Entonces, cuando avanzas en la cadena, el siguiente controlador puede leer el mismo cuerpo.

Una opción es leer todo el cuerpo usando ioutil.ReadAll() , que le da el cuerpo como un segmento de bytes.

Puede usar bytes.NewBuffer() para obtener un io.Reader de un segmento de bytes.

La última pieza que falta es convertir el io.Reader un io.ReadCloser , porque bytes.Buffer no tiene un método Close() . Para esto, puede usar ioutil.NopCloser() que envuelve un io.Reader y devuelve un io.ReadCloser , cuyo método Close() agregado será un no-op (no hace nada).

Tenga en cuenta que incluso puede modificar el contenido del segmento de bytes que utiliza para crear el "nuevo" cuerpo. Tienes control total sobre eso.

Sin embargo, se debe tener cuidado, ya que puede haber otros campos HTTP como la longitud del contenido y las sumas de verificación que pueden volverse inválidas si modifica solo los datos. Si los controladores posteriores los verifican, ¡también necesitarás modificarlos!

Inspección / modificación del cuerpo de respuesta

Si también desea leer el cuerpo de la respuesta, debe envolver el http.ResponseWriter que obtiene y pasar el contenedor a la cadena. Este contenedor puede almacenar en caché los datos enviados, que puede inspeccionar después, sobre la marcha (como los controladores posteriores le escriben).

Aquí hay un contenedor simple ResponseWriter , que simplemente almacena en caché los datos, por lo que estará disponible después de que regrese el controlador posterior:

type MyResponseWriter struct { http.ResponseWriter buf *bytes.Buffer } func (mrw *MyResponseWriter) Write(p []byte) (int, error) { return mrw.buf.Write(p) }

Tenga en cuenta que MyResponseWriter.Write() simplemente escribe los datos en un búfer. También puede optar por inspeccionarlo sobre la marcha (en el método Write() ) y escribir los datos inmediatamente en el ResponseWriter envuelto / incrustado. Incluso puede modificar los datos. Tienes el control total.

Sin embargo, se debe tener cuidado nuevamente, ya que los controladores posteriores también pueden enviar encabezados de respuesta HTTP relacionados con los datos de respuesta, como la longitud o las sumas de verificación, que también pueden invalidar si modifica los datos de respuesta.

Ejemplo completo

Poniendo las piezas juntas, aquí hay un ejemplo de trabajo completo:

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) } }) }

Estoy escribiendo mi propio logginMiddleware. Básicamente, necesito registrar el cuerpo de la solicitud y la respuesta. El problema que enfrenté es que cuando leo el cuerpo, se vacía y no puedo leerlo dos veces. Entiendo que sucede porque es de tipo ReadCloser. ¿Hay alguna manera de rebobinar el cuerpo hasta el principio?


Podría usar el paquete GetBody from Request.

Mire este comentario en el código fuente de request.go en net / http:

GetBody define una función opcional para devolver una nueva copia de Body. Se utiliza para solicitudes de clientes cuando una redirección requiere leer el cuerpo más de una vez. El uso de GetBody todavía requiere configurar el cuerpo. Para las solicitudes del servidor no se utiliza ".

GetBody func() (io.ReadCloser, error)

De esta manera, puede obtener la solicitud del cuerpo sin dejarla vacía.

Muestra:

getBody := request.GetBody copyBody, err := getBody() if err != nil { // Do something return err } http.DefaultClient.Do(request)