2012-06-12 2 views
81

Zuvor fragte ich How to get data received in Flask request, weil request.data leer war. Die Antwort erklärte, dass request.data der rohe Post-Body ist, aber leer sein wird, wenn Formulardaten analysiert werden. Wie kann ich den rohen Postkörper unbedingt bekommen?Erhalten Raw POST Körper in Python Flask unabhängig von Content-Type Header

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

Dies ist wahrscheinlich ein Implementierungsdetail von werkzeug, dem zugrunde liegenden WSGI-Mikroframework, und nicht von Flask. – jathanism

Antwort

136

Verwenden Sie request.get_data(), um die Rohdaten unabhängig vom Inhaltstyp abzurufen. Die Daten werden zwischengespeichert und Sie können anschließend beliebig auf request.data, request.json, request.form zugreifen.

Wenn Sie zuerst auf request.data zugreifen, wird get_data mit einem Argument aufgerufen, um Formulardaten zuerst zu analysieren. Wenn die Anforderung einen Formularinhaltstyp aufweist (multipart/form-data, application/x-www-form-urlencoded oder application/x-url-encoded), werden die Rohdaten verbraucht. request.data und request.json erscheinen in diesem Fall leer.

+2

Dies sollte wahrscheinlich die akzeptierte Antwort sein, jetzt, da die Bibliothek geändert wurde. –

+4

Sehr kontraintuitives Verhalten, übrigens. Wie ein Fehler. – dmitry

+0

Ftr: Die erwähnte [Quelle lebt hier] (https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/wrappers.py#L448). – dtk

25

Es gibt request.stream, wenn der MIME-Typ nicht erkannt wird.

data = request.stream.read() 
+4

Aber wird die request.stream.read() alles zurückgeben, wenn Mime-Typ erkannt wird? – ddinchev

+0

Die Dokumentation sagt nicht und ich weiß es nicht. Meine Vermutung ist nein, weil Sie den Stream nur einmal lesen können. –

+4

Ich habe einen Kommentar von Armin Ronacher gelesen, dass, wenn Sie 'request.json',' request.data' usw. verwenden, 'request.stream' leer ist (oder teilweise verbraucht). Ich kann den Kommentar nicht finden, aber aufgrund dieser Anekdote würde ich vorsichtig sein. –

14

Ich hatte gerade dieses Problem, und ich denke, einige von Ihnen könnten von meiner Lösung profitieren. Ich habe eine WSGI-Middleware-Klasse erstellt, die den rohen POST-Body aus dem Socket speichert. Ich habe den Wert in der WSGI-Variablen 'environ' gespeichert, sodass ich ihn in meiner Flask-App als request.environ ['body_copy'] bezeichnen könnte.

Sie müssen vorsichtig sein, dass die Post-Daten nicht zu groß ist, oder Sie haben möglicherweise Speicherprobleme auf Ihrem Server.

+1

Dies ist nur eine gute Lösung, wenn Sie den Content-Type-Header des Clients nicht steuern können. Wenn Sie das ändern können, ist die Antwort unten unendlich einfacher und einfacher. –

+0

Ich arbeite mit einem missgebildeten Kunden. (Ich habe keine Kontrolle über den Client.) Client sendet Content-Type: application/x-www-form-urlencoded, aber die Nutzdaten sind Roh-XML. Flask dekodiert es als Formular, gibt aber den Schlüssel als '

+0

Leider verbraucht Bottle Request Stream und es gibt keine konkrete API, um dies zu beheben, es sei denn, Sie berühren den Quellcode. Deshalb bin ich persönlich zu Falcon gewechselt. – Farsheed

4

ich endlich herausgefunden, wenn ich dies tun:

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

Dann request.data wird die Post-Daten tatsächlich hat. Dies ist der Fall, wenn Sie die Clientanforderung nicht steuern können und diese nur auf dem Server außer Kraft setzen möchten.

+0

Funktioniert nicht für mich. 'request.data' ist noch leer. Es hat nur Daten, wenn der Client 'Content-type: application/json' sendet. – fiatjaf

+0

so hacky. Nein Danke. – deweydb