Как передать HttpResponse с помощью Django

Я пытаюсь получить "привет мир" потоковых ответов, работающих на Django (1.2). Я понял, как использовать генератор и функцию 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)

Ответ 1

Вы можете отключить промежуточное ПО 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"

Ответ 2

Много промежуточного программного обеспечения django предотвратит потоковое содержимое. Большая часть этого промежуточного программного обеспечения должна быть включена, если вы хотите использовать приложение администратора django, так что это может раздражать. К счастью, это было разрешено в выпуске django 1.5. Вы можете использовать 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

Я тестировал выше на Apache 2.2 с Ubuntu 13.04. Модуль apache mod_deflate, который был включен по умолчанию в тестируемой настройке, будет буферизовать содержимое, которое вы пытаетесь передать, до тех пор, пока оно не достигнет определенного размера блока, тогда он будет gzip содержимого и отправит его в браузер. Это предотвратит работу вышеуказанного примера по желанию. Один из способов избежать этого - отключить mod_deflate, поместив следующую строку в конфигурацию apache:

SetEnvIf Request_URI ^/mysite no-gzip=1

Это обсуждается в Как отключить mod_deflate в apache2? вопрос.