Django(1.2)で動作するストリーミング応答の 'hello world'を取得しようとしています。ジェネレータとyield
関数の使用方法を見つけました。しかし、まだストリーミングされていません。それをいじっているミドルウェアがあるのではないかと思います-ETAG計算機かもしれませんが、それを無効にする方法がわかりません。
ここに私がこれまで持っているストリーミングの「こんにちは世界」があります:
def stream_response(request):
resp = HttpResponse( stream_response_generator())
return resp
def stream_response_generator():
for x in range(1,11):
yield "%s\n" % x # Returns a chunk of the response to the browser
time.sleep(1)
condition decorator を使用して、ETAGミドルウェアを無効にできます。これにより、応答がHTTP経由でストリーミングされます。これは、curl
などのコマンドラインツールで確認できます。しかし、ブラウザがストリームの応答を表示するには、おそらく十分ではありません。ブラウザーがストリーミングするときに応答を表示するように促すには、パイプの下に大量の空白をプッシュして、バッファーを強制的に埋めることができます。例は次のとおりです。
from Django.views.decorators.http import condition
@condition(etag_func=None)
def stream_response(request):
resp = HttpResponse( stream_response_generator(), content_type='text/html')
return resp
def stream_response_generator():
yield "<html><body>\n"
for x in range(1,11):
yield "<div>%s</div>\n" % x
yield " " * 1024 # Encourage browser to render incrementally
time.sleep(1)
yield "</body></html>\n"
Django=ミドルウェアはコンテンツのストリーミングを防ぎます。Django管理アプリを使用する場合は、このミドルウェアの多くを有効にする必要があります。幸いなことに、これは Django 1.5 release で解決されました。 StreamingHttpResponse を使用して、結果とそのすべてのミドルウェアをストリーミングすることを示すことができます。 Djangoはこれを認識しており、コンテンツ出力をバッファリングせずに行に送信します。コードは次のようになり、新しいStreamingHttpResponseオブジェクトを使用します。
def stream_response(request):
return StreamingHttpResponse(stream_response_generator())
def stream_response_generator():
for x in range(1,11):
yield "%s\n" % x # Returns a chunk of the response to the browser
time.sleep(1)
Apacheに関する注意
Ubuntu 13.04でApache 2.2で上記をテストしました。私がテストしたセットアップでデフォルトで有効にされたApacheモジュールmod_deflateは、特定のブロックサイズに達するまでストリーミングしようとしているコンテンツをバッファリングし、コンテンツをgzipしてブラウザに送信します。これにより、上記の例が希望どおりに動作しなくなります。これを回避する1つの方法は、Apache構成に次の行を追加してmod_deflateを無効にすることです。
SetEnvIf Request_URI ^/mysite no-gzip=1
これについては Apache2でmod_deflateを無効にする方法? の質問で詳しく説明しています。