中断响应

前面的示例有一个资源,它异步生成响应,而不是在调用其 render 方法时立即生成。当异步生成响应时,就会出现客户端连接在响应生成之前丢失的可能性。在这种情况下,通常希望完全放弃响应生成,因为一旦数据生成,就无法对其进行任何操作。本示例演示了如何收到连接丢失的通知。

本示例将基于 异步响应示例,该示例只是(如果不是非常现实地)在固定延迟后生成响应。我们将扩展该资源,以便一旦客户端连接丢失,延迟事件就会被取消,并且响应永远不会生成。

本示例依赖的功能由另一个 Request 方法提供:notifyFinish 。此方法返回一个新的 Deferred,如果请求成功响应,它将使用 None 触发,否则将使用错误触发 - 例如,如果在发送响应之前连接丢失。

该示例以熟悉的方式开始,包括必要的 Twisted 导入和一个资源类,该类使用与之前相同的 _delayedRender

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

在定义 render 方法之前,我们将定义一个 errback(errback 是一个在发生错误时被调用的回调)。这将是附加到 Deferred 的 errback,该 DeferredRequest.notifyFinish 返回。它将取消对 _delayedRender 的延迟调用。

...
    def _responseFailed(self, err, call):
        call.cancel()

最后,render 方法将像以前一样设置延迟调用,并同样返回 NOT_DONE_YET 。但是,它还将使用 Request.notifyFinish 来确保在适当的情况下调用 _responseFailed

...
    def render_GET(self, request):
        call = reactor.callLater(5, self._delayedRender, request)
        request.notifyFinish().addErrback(self._responseFailed, call)
        return NOT_DONE_YET

请注意,由于 _responseFailed 需要对延迟调用对象的引用才能取消它,因此我们将该对象传递给了 addErrback 。传递给 addErrback(或 addCallback )的任何其他参数都将在 Failure 实例之后传递给 errback,该实例始终作为第一个参数传递。在这里传递 call 表示它将传递给 _responseFailed ,在那里它被期望和需要。

这涵盖了本示例中几乎所有代码。以下是整个示例,没有中断,作为 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 _responseFailed(self, err, call):
        call.cancel()

    def render_GET(self, request):
        call = reactor.callLater(5, self._delayedRender, request)
        request.notifyFinish().addErrback(self._responseFailed, call)
        return NOT_DONE_YET

resource = DelayedResource()

将此代码放入 example.rpy 中,使用 twistd -n web --path . 启动它,然后访问 http://localhost:8080/example.rpy 。如果您等待五秒钟,您将获得页面内容。如果您在五秒钟之前中断请求,例如通过按下 Escape 键(至少在 Firefox 中),那么您将看到可能是有史以来最无聊的演示 - 没有页面内容,并且服务器日志中没有任何内容。成功!