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

Get raw POST body in Python Flask regardless of Content-Type header

以前,我问过如何在烧瓶请求中获取数据,因为request.data是空的。答案解释说,request.data是原始的post主体,但如果解析表单数据,则为空。如何无条件获取原始邮件正文?

1
2
3
4
@app.route('/', methods=['POST'])
def parse_request():
    data = request.data  # empty in some cases
    # always need raw data here, not parsed form data


使用request.get_data()获取原始数据,而不考虑内容类型。数据被缓存,您随后可以随意访问request.datarequest.jsonrequest.form

如果您首先访问request.data,它将使用参数调用get_data,首先解析表单数据。如果请求具有表单内容类型(multipart/form-dataapplication/x-www-form-urlencodedapplication/x-url-encoded,则将使用原始数据。在这种情况下,request.datarequest.json将显示为空。


当mime类型无法识别时,存在request.stream

1
data = request.stream.read()


我刚刚遇到这个问题,我想你们中的一些人可能会从我的解决方案中受益。我创建了一个wsgi中间件类,用于保存套接字中的原始post主体。我把这个值保存在wsgi变量"environ"中,这样我就可以在flask应用程序中把它称为request.environ["body_copy"]。

您需要注意的是,日志数据不太大,或者您的服务器上可能有内存问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class WSGICopyBody(object):
    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):

        from cStringIO import StringIO
        length = environ.get('CONTENT_LENGTH', '0')
        length = 0 if length == '' else int(length)

        body = environ['wsgi.input'].read(length)
        environ['body_copy'] = body
        environ['wsgi.input'] = StringIO(body)

        # Call the wrapped application
        app_iter = self.application(environ,
                                    self._sr_callback(start_response))

        # Return modified response
        return app_iter

    def _sr_callback(self, start_response):
        def callback(status, headers, exc_info=None):

            # Call upstream start_response
            start_response(status, headers, exc_info)
        return callback

app.wsgi_app = WSGICopyBody(app.wsgi_app)

request.environ['body_copy'] # This is the raw post body you can use in your flask app


我终于知道如果我这样做:

1
request.environ['CONTENT_TYPE'] = 'application/something_Flask_ignores'

那么,request.data将实际拥有post数据。如果您不能控制客户机请求,并且只想在服务器上覆盖它,那么就需要这样做。


这对我很有用:

1
2
3
4
@application.route("/getrawdata", methods=['POST'])
def getrawdata():
    #Your processing logic here
    return request.get_data()

我通过在原始数据中传递二进制字符串,在邮差中成功地测试了这一点。要使其生效,您需要在flask中导入请求包:

1
from flask import request