Ottieni il corpo POST non elaborato in Python Flask indipendentemente dall'intestazione Content-Type


131

In precedenza, ho chiesto come ottenere i dati ricevuti nella richiesta Flask perché request.dataera vuota. La risposta ha spiegato che request.dataè il corpo post grezzo, ma sarà vuoto se i dati del modulo vengono analizzati. Come posso ottenere incondizionatamente il corpo della posta grezza?

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

Risposte:


218

Utilizzare request.get_data()per ottenere i dati non elaborati, indipendentemente dal tipo di contenuto. I dati vengono memorizzati nella cache e si può poi accedere request.data, request.json, request.forma volontà.

Se accedi per request.dataprimo, chiamerà get_datacon un argomento per analizzare prima i dati del modulo. Se la richiesta ha un tipo di contenuto modulo ( multipart/form-data, application/x-www-form-urlencoded, o application/x-url-encoded), quindi i dati grezzi saranno consumati. request.datae request.jsonapparirà vuoto in questo caso.


2
Questo sembra rompersi quando si usano raven-python (Sentry), bug e soluzioni alternative qui: github.com/getsentry/raven-python/issues/457
dequis

34

request.streamè il flusso di dati grezzi passati all'applicazione dal server WSGI. Non viene eseguito alcun analisi durante la lettura, anche se di solito si desidera request.get_data()invece.

data = request.stream.read()

Il flusso sarà vuoto se è stato precedentemente letto da request.datao un altro attributo.


15

Ho creato un middleware WSGI che memorizza il corpo grezzo dallo environ['wsgi.input']stream. Ho salvato il valore nell'ambiente WSGI in modo da potervi accedere dalla request.environ['body_copy']mia app.

Questo non è necessario in Werkzeug o Flask, poiché request.get_data()otterrà i dati non elaborati indipendentemente dal tipo di contenuto, ma con una migliore gestione del comportamento HTTP e WSGI.

Questo legge l'intero corpo in memoria, il che sarà un problema se, ad esempio, viene pubblicato un file di grandi dimensioni. Questo non leggerà nulla se Content-Lengthmanca l' intestazione, quindi non gestirà le richieste di streaming.

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.datasarà vuoto se request.headers["Content-Type"]viene riconosciuto come dato del modulo, in cui verrà analizzato request.form. Per ottenere i dati non elaborati indipendentemente dal tipo di contenuto, utilizzare request.get_data().

request.datachiamate request.get_data(parse_form_data=True), che comporta il diverso comportamento dei dati del modulo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.