当然。
有传统的服务器驱动方法,其中脚本仅运行一次,但要花很长时间才能完成,因此会随即吐出部分页面:
import sys, time
sys.stdout.write('Content-Type: text/html;charset=utf-8\r\n\r\n')
print '<html><body>'
for i in range(10):
print '<div>%i</div>'%i
sys.stdout.flush()
time.sleep(1)
当将应用程序写入WSGI时,这是通过使应用程序返回一个可迭代程序来完成的,该程序输出一次要分别发送的每个要发送的块。我真的建议写WSGI。您现在可以通过CGI部署它,但是将来当您的应用需要更好的性能时,您可以通过更快的服务器/界面来部署它,而无需重写。
WSGI-over-CGI示例:
import time, wsgiref.handlers
class MyApplication(object):
def __call__(self, environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')])
return self.page()
def page(self):
yield '<html><body>'
for i in range(10):
yield '<div>%i</div>'%i
time.sleep(1)
application= MyApplication()
if __name__=='__main__':
wsgiref.handlers.CGIHandler().run(application)
请注意,您的Web服务器可能会通过添加其自身的缓冲来阻止这种方法(对于CGI 或 WSGI)。如果您使用输出转换过滤器(例如mod_deflate
自动压缩Webapp输出),通常会发生这种情况。您需要为生成部分响应的脚本关闭压缩。
这限制了您在输入新数据时逐位渲染页面。您可以通过让客户端在输入新数据时照顾更改页面来使其更漂亮,例如:
def page(self):
yield (
'<html><body><div id="counter">-</div>'
'<script type="text/javascript">'
' function update(n) {'
' document.getElementById("counter").firstChild.data= n;'
' }'
'</script>'
)
for i in range(10):
yield '<script type="text/javascript">update(%i);</script>'%i
time.sleep(1)
这依赖于客户端脚本,因此最好在末尾包含基于非脚本的备份最终输出。
一直以来,页面似乎仍在加载中。如果您不希望这样做,则需要将脚本拆分为一个只发出静态内容的第一个请求,包括客户端脚本,该客户端脚本使用一个轮询新数据的XMLHttpRequest与服务器进行核对通过,或者对于真正长期运行的情况,很多XMLHttpRequests都返回状态和任何新数据。这种方法要复杂得多,因为这意味着您必须将工作流程作为后台守护进程运行(与Web服务器分开),并使用例如在守护程序和前端CGI / WSGI请求之间传递数据。管道或数据库。