在操作内容后,在WSGI中间件中设置适当的HTTP Content-Length头

时间:2013-07-04 09:34:02

标签: python http-headers wsgi middleware werkzeug

我在基于Werkzeug的应用程序中设置了一个中间件,为我做一些JSON转义和操作(尤其是为基于Angular的REST客户端添加转义字符串JSON前缀)。

我想将整个逻辑保留在中间件层中,不要在我的基本视图类或我的基本应用程序中添加任何技巧。

因为我的中间件操纵内容我从标题中删除Content-Length标题,但我想成为一名好网友并向客户提供该信息。

不幸的是,在我操纵内容时,似乎无法再调整标题。我是否必须在管道中进一步做到这一点?在它周围包裹第二个中间件?

以下是中间件的代码:

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

2 个答案:

答案 0 :(得分:0)

您不必担心删除/添加/更改内容长度标头,服务器在发送响应时会自动处理。发送错误的长度标题可能会给您的网站查看者/互联网浏览器带来问题。

您可以在此处测试内容长度标题 - http://www.dekho-ji.com/website-diagnostics-curl-http-request-response-headers-online

答案 1 :(得分:0)

能够通过不允许将内部应用更改为start_response来更改标头,而是为其提供了收集器伪函数:

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