takes mw_instance example español django rest

django - mw_instance - Tengo un middleware en el que quiero registrar cada solicitud/respuesta. ¿Cómo puedo acceder a los datos de POST?



django middleware example (6)

Tengo este middleware

import logging request_logger = logging.getLogger(''api.request.logger'') class LoggingMiddleware(object): def process_response(self, request, response): request_logger.log(logging.DEBUG, "GET: {}. POST: {} response code: {}. response " "content: {}".format(request.GET, request.DATA, response.status_code, response.content)) return response

El problema es que la solicitud en el método process_response no tiene .POST ni .DATA ni .body. Estoy usando django-rest-framework y mis solicitudes tienen Content-Type: application / json

Tenga en cuenta que si pongo el registro en el método process_request, tiene .body y todo lo que necesito. Sin embargo, necesito tanto la solicitud como la respuesta en una sola entrada de registro.


Aquí está la solución completa que hice.

""" Api middleware module """ import logging request_logger = logging.getLogger(''api.request.logger'') class LoggingMiddleware(object): """ Provides full logging of requests and responses """ _initial_http_body = None def process_request(self, request): self._initial_http_body = request.body # this requires because for some reasons there is no way to access request.body in the ''process_response'' method. def process_response(self, request, response): """ Adding request and response logging """ if request.path.startswith(''/api/'') and / (request.method == "POST" and request.META.get(''CONTENT_TYPE'') == ''application/json'' or request.method == "GET"): request_logger.log(logging.DEBUG, "GET: {}. body: {} response code: {}. " "response " "content: {}" .format(request.GET, self._initial_http_body, response.status_code, response.content), extra={ ''tags'': { ''url'': request.build_absolute_uri() } }) return response

Nota, este

''tags'': { ''url'': request.build_absolute_uri() }

Te permitirá filtrar por url en centinela.


Es como acceder a los datos del formulario para crear un nuevo formulario.

Debe usar request.POST para esto (tal vez request.FILES es algo que también registraría).

class LoggingMiddleware(object): def process_response(self, request, response): request_logger.log(logging.DEBUG, "GET: {}. POST: {} response code: {}. response " "content: {}".format(request.GET, request.POST, response.status_code, response.content)) return response

Vea Here para las propiedades de solicitud.


Es frustrante y sorprendente que no haya un paquete de registro de solicitudes fácil de usar en Django.

Así que creé uno mismo. Échale un vistazo: https://github.com/rhumbixsf/django-request-logging.git

Utiliza el sistema de registro para que sea fácil de configurar. Esto es lo que obtienes con el nivel DEBUG:

GET/POST request url POST BODY if any GET/POST request url - response code Response body


La solución de Andrey se romperá en las solicitudes concurrentes. Necesitaría almacenar el cuerpo en algún lugar del alcance de la solicitud y buscarlo en el process_response().

class RequestLoggerMiddleware(object): def process_request(self, request): request._body_to_log = request.body def process_response(self, request, response): if not hasattr(request, ''_body_to_log''): return response msg = "method=%s path=%s status=%s request.body=%s response.body=%s" args = (request.method, request.path, response.status_code, request._body_to_log, response.content) request_logger.info(msg, *args) return response


También tenga en cuenta que response.content devuelve bytestring y no una cadena Unicode, por lo que si necesita imprimir Unicode, debe llamar a response.content.decode("utf-8") .


Todas las respuestas anteriores tienen un problema potencial: gran solicitud . Todo el mundo pasa al servidor. En Django request.body es una propiedad. (desde el marco)

@property def body(self): if not hasattr(self, ''_body''): if self._read_started: raise RawPostDataException("You cannot access body after reading from request''s data stream") try: self._body = self.read() except IOError as e: six.reraise(UnreadablePostError, UnreadablePostError(*e.args), sys.exc_info()[2]) self._stream = BytesIO(self._body) return self._body

Cuerpo de acceso al framework Django directamente solo en un caso. (desde el marco)

elif self.META.get(''CONTENT_TYPE'', '''').startswith(''application/x-www-form-urlencoded''):

Como puede ver, el cuerpo de la propiedad lee la solicitud completa en la memoria. Como resultado, su servidor puede simplemente fallar. Además, se vuelve vulnerable al ataque DoS. En este caso, sugeriría usar otro método de la clase HttpRequest. (desde el marco)

def readlines(self): return list(iter(self))

Entonces, ya no necesitas hacer esto.

def process_request(self, request): request._body_to_log = request.body

simplemente puedes hacer

def process_response(self, request, response): msg = "method=%s path=%s status=%s request.body=%s response.body=%s" args = (request.method, request.path, response.status_code, request.readlines(), response.content) request_logger.info(msg, *args) return response

EDITAR : este enfoque con request.readlines () tiene problemas. A veces no registra nada.