web-dev-qa-db-fra.com

Comment diffuser une HttpResponse avec Django

J'essaie de faire fonctionner le "bonjour" des réponses en streaming pour Django (1.2). J'ai compris comment utiliser un générateur et la fonction yield. Mais le réponse ne diffuse toujours pas. Je soupçonne qu'il y a un middleware qui se cache avec - peut-être une calculatrice ETAG? Mais je ne sais pas comment le désactiver. Quelqu'un peut-il s'il vous plaît aider?

Voici le "bonjour le monde" du 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 "%s\n" % x  # Returns a chunk of the response to the browser
        time.sleep(1)
53
muudscope

Vous pouvez désactiver le middleware ETAG en utilisant condition décorator . Cela permettra à votre réponse d'être retransmise via HTTP. Vous pouvez le confirmer avec un outil en ligne de commande comme curl. Mais cela ne suffira probablement pas pour que votre navigateur affiche la réponse pendant la diffusion. Pour encourager le navigateur à afficher la réponse pendant sa diffusion, vous pouvez pousser un tas d'espaces dans le tuyau pour forcer ses tampons à se remplir. Voici un exemple:

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"
45
Leopd

Une grande partie du middleware Django vous empêchera de diffuser du contenu. Une grande partie de ce middleware doit être activé si vous souhaitez utiliser l'application d'administration Django, donc cela peut être une gêne. Heureusement, cela a été résolu dans la version Django 1.5 . Vous pouvez utiliser la StreamingHttpResponse pour indiquer que vous souhaitez diffuser les résultats et tous les middleware qui est livré avec Django est conscient de cela et agit en conséquence pour ne pas tamponner la sortie de votre contenu mais l'envoyer directement sur 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)

Remarque sur Apache

J'ai testé ce qui précède sur Apache 2.2 avec Ubuntu 13.04. Le module Apache mod_deflate qui était activé par défaut dans la configuration que j'ai testée tamponnera le contenu que vous essayez de diffuser jusqu'à ce qu'il atteigne une certaine taille de bloc, puis il compressera le contenu et l'enverra au navigateur. Cela empêchera l'exemple ci-dessus de fonctionner comme vous le souhaitez. 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é davantage dans la question Comment désactiver mod_deflate dans Apache2? .

38
Marwan Alsabbagh