WSGI中间件是否可以修改请求主体然后传递它?

时间:2015-07-24 22:51:55

标签: python python-3.x wsgi

我正在尝试编写一个中间件,当它在正文中找到“_method”参数时,会将POST请求重写为其他方法。互联网上有人写了这段代码:

from werkzeug import Request

class MethodRewriteMiddleware(object):
    def __init__(self, app, input_name='_method'):
        self.app = app
        self.input_name = input_name

    def __call__(self, environ, start_response):
        request = Request(environ)

        if self.input_name in request.form:
            method = request.form[self.input_name].upper()

            if method in ['GET', 'POST', 'PUT', 'DELETE']:
                environ['REQUEST_METHOD'] = method

        return self.app(environ, start_response)

当我理解代码时,它解析表单,检索可能的“_method”参数,如果找到并列入白名单,它将覆盖当前方法。它适用于DELETE请求,它可以毫无问题地重写方法。但是,当我尝试发送一个定期的,非重写的POST时,这个中间件会使整个应用程序挂起。我最好的猜测是,因为我访问了中间件中的主体,所以应用程序的主体不再可用,所以它永远挂起。但是,这似乎不会影响重写请求,因此代码最深的代码路径(检查白名单)正常工作,但其他代码路径以某种方式破坏/阻止请求。

我认为这不相关,但我将这个中间件安装在Flask应用程序之上。

编辑:我认为尝试从Flask中的处理程序访问request是阻止。 Flask是否在内部使用互斥量或类似内容?

我甚至不确定如何调试它。

1 个答案:

答案 0 :(得分:0)

environ是一个带有wsgi.input键的字典,它是一个流对象。执行您要查找的内容的手动方法是读取数据,进行任何更改,然后创建新字符串以替换environ字典中的旧流。下面的示例(没有任何错误处理或其他重要事项)允许您使用请求正文:

def __call__(self, environ, start_response):
    body = environ['wsgi.input'].read()
    ... do stuff to body ...
    new_stream = io.ByteIO(modified_body)
    environ['wsgi.input'] = new_stream
    return self.app(environ, start_response)