153

以前,我问过如何获取 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
4

4 回答 4

252

用于request.get_data()获取原始数据,无论内容类型如何。数据被缓存,您随后可以随意访问request.data, request.json, request.form

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

于 2014-05-27T21:06:57.973 回答
41

request.stream是由 WSGI 服务器传递给应用程序的原始数据流。阅读时不进行解析,尽管您通常需要request.get_data()

data = request.stream.read()

如果之前由request.data其他属性读取,则该流将为空。

于 2012-06-12T16:25:25.097 回答
18

我创建了一个 WSGI 中间件,用于存储流中的原始主体environ['wsgi.input']。我将值保存在 WSGI 环境中,因此我可以从request.environ['body_copy']我的应用程序中访问它。

这在 Werkzeug 或 Flask 中不是必需的,因为request.get_data()无论内容类型如何都会获取原始数据,但可以更好地处理 HTTP 和 WSGI 行为。

这会将整个正文读入内存,例如,如果发布了一个大文件,这将是一个问题。如果缺少标头,这将不会读取任何内容Content-Length,因此它不会处理流请求。

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)
request.environ['body_copy']
于 2012-06-22T20:29:43.267 回答
8

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

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

于 2014-10-28T21:20:00.283 回答