2010-05-27 5 views
48

Я пытаюсь получить «привет мир» потоковых ответов, работающих на Django (1.2). Я понял, как использовать генератор и функцию yield. Но ответ по-прежнему не транслируется. Я подозреваю, что есть промежуточное программное обеспечение, которое с этим связано - возможно, ETAG-калькулятор? Но я не уверен, как отключить его. Может ли кто-нибудь помочь?Как передать HttpResponse с Django

Вот «привет мир» потокового, что у меня до сих пор:

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

@ Tomasz: спецификация протокола WSGI http://www.python.org/dev/peps/pep-0333/ –

ответ

42

Вы можете отключить ETAG промежуточное программное обеспечение с помощью condition decorator. Это даст вам ответ на поток через 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" 
+3

В моих тестах Django GZipMiddleware может помешать этому работать. – Xealot

+1

Да, я ожидаю, что многие посредники, вероятно, будут вступать в противоречие с этим, поэтому, если он не работает, попробуйте отключить все ваши посредники и снова включить их поэтапно. GZip требует наличия всего ответа, прежде чем он сжимает его, поэтому он не позволит вам передавать поток. – Leopd

+1

@Xealot: У меня такая же проблема с GzipMiddleware. Подал ошибку, потому что это промежуточное ПО не поддерживает генераторы (он фактически очищает генератор случайно): [Django ticket # 15066] (http://code.djangoproject.com/ticket/15066) – AndiDog

33

Много промежуточного программного обеспечения 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

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

SetEnvIf Request_URI ^/mysite no-gzip=1 

Это обсуждается больше в How to disable mod_deflate in apache2? вопрос.

+0

Он работает! но как я должен отображать его в шаблоне 'real-time'? В настоящее время я использую Javascript с вызовом ajax .. но он публикует вывод .. только после того, как он закончил обработку. Так что это не 'Streaming', когда дело доходит до его перевода в« браузер ». Любая помощь будет оценена.Спасибо :) –

+0

@FirstBlood С помощью ajax вы можете получать обратные вызовы по мере их потоковой передачи, а не только после завершения загрузки. Просмотрите этот ответ http://stackoverflow.com/a/4488132/1699750, чтобы показать прогресс в вызове Ajax. –

+0

Спасибо .. Я хочу достигнуть статуса вывода Ping. Для печати в режиме реального времени в браузере. Итак, например: ping -c 3 www.google.com' .. как командное приглашение выводит результат .. возможно ли в Django вывести вывод в браузер, когда я читаю через 'subprocess'? Я попробовал «StreamingHttpResponse», но, похоже, он не работает в режиме реального времени. Я даже попытался установить «заголовки: Keep-Alive» .. но никакого эффекта :( –

Смежные вопросы