如何在Pylons中“刷新”响应(类似ASP Response.Write)

0 投票
3 回答
570 浏览
提问于 2025-04-15 20:17

我有一个Pylons控制器,它是通过jQuery的$.ajaxSubmit()来调用的。这个控制器执行一个需要很长时间才能完成的操作,我希望它能在整个输出结果出来之前,先返回一些进度消息。作为一个简单的概念验证,我尝试了以下代码:

response.body_file.write('<script>OnExecutionProgress("Starting");</script>\n')
time.sleep(2)
response.body_file.write('<script>OnExecutionProgress("Finished");</script>\n')

但是,这段代码并没有立即把第一条消息返回给客户端,而是等到所有内容都处理完了才一起返回。

我之前在ASP.NET中做过类似的事情,使用了Response.Write()Response.Flush(),效果很好。不过在Pylons中调用response.body_file.flush()似乎没有什么效果。

3 个回答

0

你可以一次“产出”一部分结果。试着写一个生成器,每次只产出一小块结果,这样可能会有效果。这个方法使用了分块传输编码

0

这确实有点像个小技巧,但在pylons中,它的工作方式和ASP.NET是一样的。我在Paste服务器上测试过。

正如Alex Martelli所说,在这种情况下,使用Comet会更好。分块发送脚本可能会导致以下问题:

  1. 不被支持,并且依赖于服务器的实现;
  2. 不可靠,因为你无法处理连接超时;
  3. 服务器需要为每个连接分配单独的线程,这在高负载的网站上可能会成为性能瓶颈。

首先,你应该在development.ini中关闭调试功能:

debug = false

这里是一个控制器的代码:

class HelloController(BaseController):
    def index(self):
        header = '''\
<html><head><title>test page</title>
<script type="text/javascript">
function foo(i) {
document.getElementById('counter').innerHTML = i;
}
</script>
</head>
<body>
<div id="counter">
</div>
'''
        footer = '''\
</body>
</html>
'''
        progress = ('<script>foo(%i);</script>' % i for i in xrange(0,101,2))
        def f():
            yield header
            for script in progress:
                time.sleep(1)
                yield script
            yield footer
        return f()
1

HTTP本身并不支持你想要的那种“流式传输”功能——它是一种请求/响应的协议,没有符合协议的方式可以发送“部分响应”。你可能在寻找所谓的Comet技术。一个简单的“使用pylons的comet”示例可以在这里找到。

撰写回答