异步响应¶
在所有前面的示例中,所呈现的资源示例都立即生成了响应。然而,Twisted Web 最重要的功能之一是能够在较长时间内生成响应,同时让服务器能够自由地响应其他请求。换句话说,异步地。在本节中,我们将编写一个这样的资源。
异步生成响应的资源在许多方面与同步生成响应的资源类似。无论哪种方式,都使用相同的基类,Resource
;使用相同的渲染方法。但是,存在三个基本差异。
首先,资源不返回用作响应主体的字符串,而是使用 Request.write
。此方法可以重复调用。每次调用都会将另一个字符串追加到响应主体。其次,当整个响应主体已传递给 Request.write
时,应用程序必须调用 Request.finish
。顾名思义,这将结束响应。最后,为了使 Twisted Web 在渲染方法返回后立即不结束响应,渲染方法必须返回 NOT_DONE_YET
。请考虑以下示例
from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from twisted.internet import reactor
class DelayedResource(Resource):
def _delayedRender(self, request):
request.write(b"<html><body>Sorry to keep you waiting.</body></html>")
request.finish()
def render_GET(self, request):
reactor.callLater(5, self._delayedRender, request)
return NOT_DONE_YET
如果您不熟悉 reactor 的 callLater
方法,您只需要知道,在上面的示例中,它安排了在从该渲染方法调用 callLater
约 5 秒后运行 self._delayedRender(request)
,并且它立即返回。
在本示例中可以看到前面提到的所有三个元素。资源使用 Request.write
设置响应主体。它在整个主体指定后使用 Request.finish
(在本例中,只使用一次调用 write)。最后,它从其渲染方法返回 NOT_DONE_YET
。因此,您拥有了使用 Twisted Web 进行异步渲染。
以下是一个基于此资源类的完整 rpy 脚本(如果您需要有关 rpy 脚本的提醒,请参阅 前面的示例)
from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from twisted.internet import reactor
class DelayedResource(Resource):
def _delayedRender(self, request):
request.write(b"<html><body>Sorry to keep you waiting.</body></html>")
request.finish()
def render_GET(self, request):
reactor.callLater(5, self._delayedRender, request)
return NOT_DONE_YET
resource = DelayedResource()
将此源代码放入一个 .rpy
文件中,并使用 twistd -n web --path /directory/containing/script/.
启动一个服务器。您将看到加载页面需要 5 秒。如果您尝试在第一个页面完成之前加载第二个页面,它也将从您请求它的时间开始需要 5 秒(但不会因任何其他未完成的请求而延迟)。
在异步生成响应时,还需要考虑的一点是,客户端可能不会等待获取其请求的响应。一个 后续示例 演示了如何检测客户端是否已放弃请求,以及服务器是否不应该费心完成生成其响应。