StreamingHttpResponse response length in a stats middleware

134 views
Skip to first unread message

Stefano Tranquillini

unread,
Jan 18, 2017, 6:42:42 AM1/18/17
to Django users
Hi there,

I'm using the StreamingHttpResponse to stream a response, it works great. Now, I've a middleware that measures the size of req/response that users do.
For normal HttpResponse i use len(response.content) [i know that it does not give the bytes, but it's pretty close], for the streaming I can't, and I can't use the streaming_content as well.

the docs says ` Because the content can’t be accessed, many middlewares can’t function normally.`
Thus, is there a way to get the length of the response for a StreamingHttpResponse?

If I would be able to know the size of the response at some point in time (it's an iterator, so i just need to count) and i could put it in the request object, how can I make it working with the middleware? beacuse the process_response is fired just after the first yield, no?

Tom Evans

unread,
Jan 18, 2017, 9:57:27 AM1/18/17
to django...@googlegroups.com
This is for 1.8 middleware, same method can be applied to 1.10

It's not very clean, but from your middleware you can return a new
response object. The new object would also be a streaming response,
but for each chunk it emits (by calling the generator on the original
response), it would also count the size of the chunk and store a
rolling sum on the response object. After the final chunk is emitted,
your logging middleware can then be called with the resulting value.
Something like:

class WrappedStreamingResponse(StreamingHttpResponse):
def __init__(self, orig_response, middleware):
self.orig_response = orig_response
self.middleware = middleware
self.response_length = 0
super(WrappedStreamingResponse, self).__init__(self.chunks())

def chunks(self):
for chunk in self.orig_response.streaming_content:
self.response_length += len(chunk)
yield chunk
self.middleware.log_response_size(self.orig_response, self.response_length)


class MeasureMiddleware:
def process_response(self, request, response):
if response.streaming:
return WrappedStreamingResponse(response, self)
else:
self.log_response_size(response, len(response.content))

def log_response_size(self, response, length):
pass

Cheers

Tom

PS: 1 big caveat for this is that if a middleware class returns a new
response, middleware classes further down the chain are not called at
all, so StreamingHttpResponse would not get handled by the same
middleware as a regular HttpResponse.
Reply all
Reply to author
Forward
0 new messages