Получите исходное тело POST в Python Flask независимо от заголовка Content-Type

Ранее я спросил Как получить данные, полученные в запросе 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

Ответ 1

Используйте request.get_data(), чтобы получить необработанные данные независимо от типа содержимого. Данные кэшируются, и вы можете впоследствии получить доступ к request.data, request.json, request.form по желанию.

Если вы сначала запустите request.data, он вызовет get_data с аргументом для анализа данных формы сначала. Если запрос имеет тип содержимого формы (multipart/form-data, application/x-www-form-urlencoded или application/x-url-encoded), тогда необработанные данные будут потребляться. request.data и request.json в этом случае будут пустыми.

Ответ 2

Там request.stream, когда тип mime не распознается.

data = request.stream.read()

Ответ 3

У меня была эта проблема, и я думаю, что некоторые из вас могут извлечь выгоду из моего решения. Я создал класс промежуточного ПО WSGI, который сохраняет исходный корпус POST из сокета. Я сохранил значение в переменной WSGI 'environ', поэтому я мог ссылаться на него как request.environ ['body_copy'] в моем приложении Flask.

Вам нужно быть осторожным, чтобы почтовые данные были не слишком большими или у вас могут быть проблемы с памятью на вашем сервере.

class WSGICopyBody(object):
    def __init__(self, application):
        self.application = application

    def __call__(self, environ, start_response):

        from cStringIO import StringIO
        length = environ.get('CONTENT_LENGTH', '0')
        length = 0 if length == '' else int(length)

        body = environ['wsgi.input'].read(length)
        environ['body_copy'] = body
        environ['wsgi.input'] = StringIO(body)

        # Call the wrapped application
        app_iter = self.application(environ, 
                                    self._sr_callback(start_response))

        # Return modified response
        return app_iter

    def _sr_callback(self, start_response):
        def callback(status, headers, exc_info=None):

            # Call upstream start_response
            start_response(status, headers, exc_info)
        return callback

app.wsgi_app = WSGICopyBody(app.wsgi_app)

request.environ['body_copy'] # This is the raw post body you can use in your flask app

Ответ 4

Наконец-то я понял, что сделаю это:

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

Тогда request.data будет фактически иметь данные сообщения. Это значит, что вы не можете контролировать запрос клиента и хотите просто переопределить его на сервере.