Comment diffuser un HttpResponse avec Django
J'essaie de faire fonctionner le' hello world ' des réponses en streaming pour Django (1.2). J'ai compris comment utiliser un générateur et la fonction yield
. Mais la réponse toujours pas en streaming. Je soupçonne qu'il y a un middleware qui s'en mêle - peut-être une calculatrice ETAG? Mais je ne suis pas sûr de savoir comment le désactiver. Quelqu'un peut-il aider s'il vous plaît?
Voici le "hello world" de streaming que j'ai jusqu'à présent:
def stream_response(request):
resp = HttpResponse( stream_response_generator())
return resp
def stream_response_generator():
for x in range(1,11):
yield "%sn" % x # Returns a chunk of the response to the browser
time.sleep(1)
2 réponses
Vous pouvez désactiver le middleware ETAG à l'aide du décorateur de condition . Cela permettra à votre réponse de revenir en flux sur HTTP. Vous pouvez le confirmer avec un outil de ligne de commande comme curl
. Mais ce ne sera probablement pas suffisant pour que votre navigateur affiche la réponse au fur et à mesure. Pour encourager le navigateur à afficher la réponse lors du flux, vous pouvez pousser un tas d'Espaces Dans le tuyau pour forcer ses tampons à remplir. Exemple suivant:
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"
Une grande partie du middleware django vous empêchera de diffuser du contenu. Une grande partie de ce middleware doit être activée si vous voulez utiliser l'application d'administration django, donc cela peut être un ennui. Heureusement, cela a été résolu dans la version django 1.5 . Vous pouvez utiliser le StreamingHttpResponse pour indiquer que vous souhaitez diffuser les résultats et que tout le middleware fourni avec django en est conscient et agit en conséquence pour ne pas mettre en mémoire tampon votre sortie de contenu mais l'envoyer directement en bas de la ligne. Votre code ressemblerait alors à ce qui suit pour utiliser le nouvel objet 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)
Note sur Apache
J'ai testé ce qui précède sur Apache 2.2 avec Ubuntu 13.04. Le module Apache mod_deflate qui a été activé par défaut dans la configuration que j'AI testée va tamponner le contenu que vous essayez de diffuser jusqu'à ce qu'il atteigne une certaine taille de bloc, puis il va gzip le contenu et l'envoyer au navigateur. Cela empêchera l'exemple ci-dessus de fonctionner comme souhaité. Une façon d'éviter cela est de désactiver mod_deflate en mettant la ligne suivante dans votre configuration apache:
SetEnvIf Request_URI ^/mysite no-gzip=1
Ceci est discuté plus dans le Comment désactiver mod_deflate dans apache2? question.