1

我在基于 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
4

2 回答 2

1

可以通过不允许内部应用程序更改标题,而是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
于 2020-05-26T14:26:29.833 回答
0

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

您可以在此处测试 Content-length 标头 - http://www.dekho-ji.com/website-diagnostics-curl-http-request-response-headers-online

于 2013-07-04T14:41:16.253 回答