开发者

How to "flush" the response in Pylons (similar to ASP Response.Write)

I have a Pylons controller that is called via jQuery $.ajaxSubmit(). It executes a long-running operation and I want to have it return progress messages before the entire output is available. As a simple proof of concept I've tried this:

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

However, this doesn't return the first message to the client immediately - the entire output is returned only at the end.

I've done something like this previously in ASP.NET using Response.Write() and Response.Flush() and it worked well. Calling response.bod开发者_高级运维y_file.flush() in Pylons seems to make no difference, though.


Natively, HTTP does not support the "streaming" you appear to desire -- it's a request/response protocol and there's no protocol-compliant way to send "part of a response". Rather, you may be looking for so-called Comet techniques. A bare-bone example of "comet with pylons" is here.


It's definitely a hack, but in pylons it works the same way as in ASP.NET. I've tested it on Paste server.

As Alex Martelli said it's better to use Comet in this case. Feeding script chunk by chunk could lead to the following problems:

  1. it's unsupported and server implementation dependent;
  2. unreliable since you can't handle connection timeouts;
  3. server need to allocate separate thread for each connection which could became performance bottleneck on high-load sites.

First of all you should turn off debugging in development.ini:

debug = false

Here is a controller code:

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()


You can "yield" your result chunk at a time. Try writing a generator that yields results chunk at a time and it will probably work. It uses http://en.wikipedia.org/wiki/Chunked_transfer_encoding.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜