web-dev-qa-db-ja.com

Content-Typeヘッダーに関係なく、POST Pythonの未加工のFlask本文を取得します

以前は、request.dataが空だったため、 Flaskリクエストで受信したデータを取得する方法 を要求しました。回答では、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
117
ddinchev

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

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

198
miracle2k

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

data = request.stream.read()

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

27
jd.

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

request.get_data()はコンテンツタイプに関係なく生データを取得するため、これはWerkzeugやFlaskでは必要ありませんが、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']
14
jhaski

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

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

5
KevinH

これは私のために働く:

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

Raw Dataにバイナリ文字列を渡すことで、Postmanでこれを正常にテストしました。これを機能させるには、フラスコにリクエストパッケージをインポートする必要があります。

from flask import request
0
rahul4data