web-dev-qa-db-ja.com

flask make_response with large files

したがって、私はファイルI/Oやメモリの制限などを備えており、Webアプリケーションがフラスコのmake_response。次のコードは小さなファイル(<〜1GB)で機能しますが、大きなファイルに入るとMemoryError例外が発生します。

raw_bytes = ""
with open(file_path, 'rb') as r:
    for line in r:
        raw_bytes = raw_bytes + line
response = make_response(raw_bytes)
response.headers['Content-Type'] = "application/octet-stream"
response.headers['Content-Disposition'] = "inline; filename=" + file_name
return response

2 GBを超えるバイナリデータを文字列に挿入することはおそらく大きな問題だと思いますが、これらのファイルダウンロードの黒魔術を達成するための代替手段は知りません。誰かがファイルをダウンロードするための分厚い[?]またはバッファリングされたアプローチで私を正しい軌道に乗せることができるか、またはこのことについてのより深い理解を促進するためにいくつかの中間レベルのリソースに私を向けることができれば、私はそれを大いに感謝します。ありがとう!

18
SheffDoinWork

ストリーミングコンテンツ のドキュメントを参照してください。基本的に、データのチャンクを生成する関数を作成し、一度に全体ではなく、そのジェネレーターを応答に渡します。 FlaskそしてWebサーバーが残りを行います。

_from flask import stream_with_context, Response

@app.route('/stream_data')
def stream_data():
    def generate():
        # create and return your data in small parts here
        for i in xrange(10000):
            yield str(i)

    return Response(stream_with_context(generate()))
_

ファイルが静的な場合は、代わりに send_from_directory() を利用できます。ドキュメントでは、nginxまたはX-SendFileをサポートする別のサーバーを使用して、データの読み取りと送信が効率的になるようにアドバイスしています。

24
davidism

試みの問題は、最初に完全なコンテンツを「raw_bytes」に読み込むため、大きなファイルを使用すると、すべてのメモリを使い果たしてしまうことです。

それを解決するための複数のオプションがあります:

コンテンツのストリーミング

Davidismの回答で説明したように、intレスポンスを渡したジェネレータを使用できます。これは、大きなファイルを少しずつ処理し、それほど多くのメモリを必要としません。

ストリーミングは、ジェネレータからだけでなく、ファイルからも行うことができます この回答に示されています

フラスコ経由で静的ファイルを提供する

ファイルが静的な場合は、Flaskを構成して静的ファイルを提供する方法を検索してください。これらは自動的にストリーミングで提供されます。

Apacheまたはnginx(またはその他のWebサーバー)を介して静的ファイルを提供する

ファイルが静的であると仮定すると、本番環境ではFlaskアプリの前にリバースプロキシを使用してサービスを提供します。これにより、アプリの負荷が軽減されるだけでなく、より高速に動作します。

3
Jan Vlcinsky