Question

I have a middleware set up in a Werkzeug based app to do some JSON escaping and manipulation for me (especially prefixing JSON with an escape string for an Angular-based REST-client).

I'd like to keep the whole logic in the middleware layer and don't add any tricks to my base view classes or my base app.

Because my middleware manipulates the content I strip the Content-Length header from headers, but I want to be a good netizen and provide the client with that information.

Unfortunately at the point where I have manipulated the content there seems to be no way to adjust headers anymore. Do I have to do this further down the pipeline? Wrap a second middleware around it?

Here's the code to the middleware:

class ContentManipulatingMiddle(object):
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        app = self.app

        def start_unpack_data(status, response_headers, exc_info=None):
            # we need to strip content-length
            response_headers = [ (name, value)
                for name, value in response_headers
                if name.lower() != 'content-length' ]

            return start_response(status, response_headers, exc_info)

        app_iter = app(environ, start_unpack_data)

        data = []
        for item in app_iter:
            # do some content manipulation
            data.append(manipulate_content(item))

        # content length has changed, i should reset the content-length header
        # but at this point, how?

        return data
Était-ce utile?

La solution 2

You dont need to worry about deleting/adding/changing content-length header, that will be auto handled by the server when it sends out the response. Sending a wrong length header might create problems for your website viewers / internet browsers.

You can test the Content-length headers here - http://www.dekho-ji.com/website-diagnostics-curl-http-request-response-headers-online

Autres conseils

Got able to change the headers by not allowing the inner app to start_response, providing it a collector dummy function instead:

class MyMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        inner_status = None
        inner_headers = []
        inner_exc_info = None

        def start_response_collector(status, headers, exc_info=None):
            # Just collects the inner response headers, to be modified before sending to client
            nonlocal inner_status, inner_headers, inner_exc_info
            inner_status = status
            inner_headers = headers
            inner_exc_info = exc_info
            # Not calling start_response(), as we will modify the headers first.
            return None

        # populates the inner_* vars, as triggers inner call of the collector closure
        response_iter = self.app(environ, start_response_collector)

        # removes the content-length, if exists
        headers = [(k, v) for k, v in inner_headers if k.lower() != 'content-length']

        inner_body = b"".join(response_iter)

        ### MANIPULATE YOUR `inner_body` HERE ###
        # E.g. producing a final_body
        final_body = b'DEADBEEF'

        final_body_length = len(final_body)
        headers.append(('Content-Length', str(final_body_length)))

        # Remember to send the modified headers!
        start_response(inner_status, headers, inner_exc_info)
        return final_body
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top