簡體   English   中英

無論 Content-Type 標頭如何,都可以在 Python Flask 中獲取原始 POST 正文

[英]Get raw POST body in Python Flask regardless of Content-Type header

之前問過如何獲取 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

無論內容類型如何,都使用request.get_data()獲取原始數據。 數據被緩存,隨后您可以隨意訪問request.datarequest.jsonrequest.form

如果您首先訪問request.data ,它將首先調用帶有參數的get_data來解析表單數據。 如果請求具有表單內容類型( multipart/form-dataapplication/x-www-form-urlencodedapplication/x-url-encoded ),則將使用原始數據。 在這種情況下request.datarequest.json將顯示為空。

request.stream是 WSGI 服務器傳遞給應用程序的原始數據流。 讀取時不進行解析,盡管您通常需要request.get_data()代替。

data = request.stream.read()

如果之前由request.data或其他屬性讀取,則該流將為空。

我創建了一個 WSGI 中間件,用於存儲來自environ['wsgi.input']流的原始正文。 我將值保存在 WSGI 環境中,以便我可以從我的應用程序中的request.environ['body_copy']訪問它。

這在 Werkzeug 或 Flask 中不是必需的,因為request.get_data()將獲取原始數據而不管內容類型如何,但可以更好地處理 HTTP 和 WSGI 行為。

這會將整個正文讀入內存,如果例如發布大文件,這將是一個問題。 如果缺少Content-Length標頭,這將不會讀取任何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']

如果request.headers["Content-Type"]被識別為表單數據, request.data將為空,它將被解析為request.form 無論內容類型如何,都要獲取原始數據,請使用request.get_data()

request.data調用request.get_data(parse_form_data=True) ,這導致表單數據的不同行為。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM