无论Content-Type标头如何,都可以在Python Flask中获取原始POST主体

ddi*_*hev 127 python werkzeug flask

以前,我问过如何获取Flask请求中收到的数据,因为它request.data是空的.答案解释request.data为原始帖子正文,但如果解析表单数据则为空.如何无条件地获得原始邮政体?

@app.route('/', methods=['POST'])
def parse_request():
    data = request.data  # empty in some cases
    # always need raw data here, not parsed form data
Run Code Online (Sandbox Code Playgroud)

mir*_*e2k 206

使用request.get_data()获得的原始数据,而不管内容类型.该数据被缓存,您可以随后访问request.data,request.json,request.form随意.

如果您request.data先访问,它将get_data使用参数调用以首先解析表单数据.如果请求具有形式的内容类型(multipart/form-data,application/x-www-form-urlencoded,或application/x-url-encoded),则原始数据将被消耗.request.data并且request.json在这种情况下将显示为空.

  • 在使用raven-python(Sentry),bug和变通方法时,这似乎打破了:https://github.com/getsentry/raven-python/issues/457 (2认同)

jd.*_*jd. 30

还有request.stream,当无法识别的MIME类型.

data = request.stream.read()
Run Code Online (Sandbox Code Playgroud)


小智 15

我刚刚遇到这个问题,我想你们中的一些人可能会从我的解决方案中受益.我创建了一个WSGI中间件类,它从套接字中保存原始POST主体.我将值保存在WSGI变量'environ'中,因此我可以在Flask应用程序中将其称为request.environ ['body_copy'].

您需要注意后期数据不是太大,或者您的服务器上可能存在内存问题.

from io import BytesIO

class WSGICopyBody(object):
    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):
        length = int(environ.get('CONTENT_LENGTH') or 0)
        body = environ['wsgi.input'].read(length)
        environ['body_copy'] = body
        # replace the stream since it was exhausted by read()
        environ['wsgi.input'] = BytesIO(body)
        return self.application(environ, start_response)

app.wsgi_app = WSGICopyBody(app.wsgi_app)
Run Code Online (Sandbox Code Playgroud)


小智 5

request.data如果request.headers["Content-Type"]被识别为表单数据,则将为空,并将其解析为request.form。要获取原始数据而不管内容类型如何,请使用request.get_data()

request.data调用request.get_data(parse_form_data=True),这导致表单数据的行为不同。