Nhận phần thân POST thô trong Python Flask bất kể tiêu đề Kiểu nội dung


131

Trước đây, tôi đã hỏi Làm thế nào để nhận dữ liệu nhận được trong yêu cầu Flaskrequest.datatrống. Câu trả lời giải thích rằng đó request.datalà phần thân bài thô, nhưng sẽ trống nếu dữ liệu biểu mẫu được phân tích cú pháp. Làm thế nào tôi có thể có được cơ thể bài thô vô điều kiện?

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

Câu trả lời:


218

Sử dụng request.get_data()để có được dữ liệu thô, bất kể loại nội dung. Dữ liệu được lưu trữ và bạn có thể sau đó truy cập request.data, request.json, request.formtheo ý thích.

Nếu bạn truy cập request.datatrước, nó sẽ gọi get_datavới một đối số để phân tích dữ liệu biểu mẫu trước. Nếu yêu cầu có một loại nội dung hình thức ( multipart/form-data, application/x-www-form-urlencodedhoặc application/x-url-encoded) sau đó các dữ liệu thô sẽ được tiêu thụ. request.datarequest.jsonsẽ xuất hiện trống rỗng trong trường hợp này.


2
Điều này dường như bị phá vỡ khi sử dụng raven-python (Sentry), lỗi và cách giải quyết tại đây: github.com/getsentry/raven-python/issues/457
dequis 17/03/2016

34

request.streamlà luồng dữ liệu thô được máy chủ WSGI truyền đến ứng dụng. Không có phân tích cú pháp được thực hiện khi đọc nó, mặc dù bạn thường muốn request.get_data()thay thế.

data = request.stream.read()

Luồng sẽ trống nếu trước đó nó được đọc bởi request.datahoặc thuộc tính khác.


15

Tôi đã tạo một phần mềm trung gian WSGI lưu trữ phần thô từ environ['wsgi.input']luồng. Tôi đã lưu giá trị trong môi trường WSGI để tôi có thể truy cập nó từ request.environ['body_copy']trong ứng dụng của mình.

Điều này không cần thiết trong Werkzeug hoặc Flask, vì request.get_data()sẽ nhận được dữ liệu thô bất kể loại nội dung, nhưng với việc xử lý tốt hơn hành vi HTTP và WSGI.

Điều này đọc toàn bộ cơ thể vào bộ nhớ, đây sẽ là một vấn đề nếu ví dụ một tập tin lớn được đăng. Điều này sẽ không đọc bất cứ điều gì nếu Content-Lengthtiêu đề bị thiếu, vì vậy nó sẽ không xử lý các yêu cầu phát trực tuyến.

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.datasẽ trống nếu request.headers["Content-Type"]được nhận dạng là dữ liệu biểu mẫu, dữ liệu này sẽ được phân tích cú pháp request.form. Để có được dữ liệu thô bất kể loại nội dung, sử dụng request.get_data().

request.datacác cuộc gọi request.get_data(parse_form_data=True), dẫn đến hành vi khác nhau cho dữ liệu biểu mẫu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.