异步响应

在所有前面的示例中,所呈现的资源示例都立即生成了响应。然而,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 秒(但不会因任何其他未完成的请求而延迟)。

在异步生成响应时,还需要考虑的一点是,客户端可能不会等待获取其请求的响应。一个 后续示例 演示了如何检测客户端是否已放弃请求,以及服务器是否不应该费心完成生成其响应。