2010-05-27 80 views
48

我正試圖獲得Django(1.2)工作流式響應的'hello world'。我想出瞭如何使用發生器和yield函數。但是響應仍然沒有流式傳輸。我懷疑是否有一箇中間件正在使用它 - 也許ETAG計算器?但我不知道如何禁用它。有人可以幫忙嗎?如何使用Django流式傳輸HttpResponse

這裏的「世界你好」流的,我到目前爲止有:

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/ – 2010-05-27 17:35:01

回答

42

您可以禁用使用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" 
+3

在我的測試中,Django GZipMiddleware可以防止這種情況發生。 – Xealot 2010-12-21 05:55:11

+1

是的,我預計很多中間件很可能會混淆它,所以如果它不起作用,請嘗試禁用所有中間件並逐步重新啓用它們。 GZip在壓縮之前需要整個響應,所以它不會讓你流式傳輸。 – Leopd 2011-01-03 01:25:24

+1

@Xealot:我遇到了GzipMiddleware的類似問題。提交了一個錯誤,因爲該中間件不支持生成器(它實際上意外清除了生成器):[Django ticket#15066](http://code.djangoproject.com/ticket/15066) – AndiDog 2011-01-12 23:54:49

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

我與Ubuntu 13.04測試上述在Apache 2.2。默認情況下,在我測試的設置中啓用的apache模塊mod_deflate將會緩存您嘗試流式傳輸的內容,直到它達到特定的塊大小,然後它將gzip內容並將其發送到瀏覽器。這將阻止上述示例按需要工作。避免這種情況的一種方法是通過將下面一行在你的Apache配置禁用mod_deflate模塊:

SetEnvIf Request_URI ^/mysite no-gzip=1 

這是討論多在How to disable mod_deflate in apache2?問題。

+0

它的工作原理!但我應該如何將它呈現給模板「實時」?目前我正在使用Ajax調用Javascript ......但只有當它完成處理時纔會發佈輸出..所以當它將其呈現給瀏覽器時,它不是'Streaming'。任何幫助,將不勝感激..謝謝:) – 2013-11-05 20:56:18

+0

@FirstBlood用ajax你可以得到回調,因爲它是流式傳輸,而不僅僅是下載完成。查看這個答案http://stackoverflow.com/a/4488132/1699750顯示Ajax調用的進度。 – 2013-11-06 12:02:19

+0

謝謝..我想實現'Ping'輸出狀態..在瀏覽器上實時打印..因此,例如:'ping -c 3 www.google.com' .. ..命令提示符如何給出輸出..是否有可能在'Django'中,通過'subprocess'讀取輸出到瀏覽器?我嘗試了'StreamingHttpResponse',但它似乎不實時流..我甚至嘗試設置'標題:保持活着...... ..但沒有影響:( – 2013-11-06 20:30:40