2010-05-27 48 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