Content-Typeヘッダーに関係なく、Python Flaskで生のPOST本文を取得する


131

以前は空だったので、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

回答:


218

request.get_data()コンテンツタイプに関係なく、生データを取得するために使用します。データはキャッシュされ、後でrequest.datarequest.jsonに自由にアクセスできますrequest.form

request.data最初にアクセスするとget_data、最初にフォームデータを解析する引数を指定して呼び出されます。要求が(フォームコンテンツタイプを有する場合multipart/form-dataapplication/x-www-form-urlencodedまたはapplication/x-url-encoded)その後、生データが消費されます。request.dataそしてrequest.jsonこの場合には何も表示されます。


2
これは、raven-python(Sentry)、バグ、および回避策を使用すると壊れるようです:github.com/getsentry/raven-python/issues/457
dequis

34

request.streamWSGIサーバーによってアプリケーションに渡される生データのストリームです。それを読むとき、通常はrequest.get_data()代わりに必要とするものの、解析は行われません。

data = request.stream.read()

以前にrequest.dataまたは別の属性によって読み取られた場合、ストリームは空になります。


15

environ['wsgi.input']ストリームからの未加工のボディを格納するWSGIミドルウェアを作成しました。request.environ['body_copy']アプリ内からアクセスできるように、値をWSGI環境に保存しました。

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']

6

request.dataがにrequest.headers["Content-Type"]解析されるフォームデータとして認識されると、空になりますrequest.form。コンテンツタイプに関係なく生データを取得するには、を使用しますrequest.get_data()

request.dataを呼び出しますrequest.get_data(parse_form_data=True)。これにより、フォームデータの動作が異なります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.