动态 URL 分发

上一个示例 中,我们介绍了如何静态配置 Twisted Web 以在不同的 URL 上提供不同的内容。本示例的目的是向您展示如何动态地执行此操作。建议您阅读上一部分(如果您还没有阅读),以了解使用 Twisted Web 的 resource API 时如何处理 URL。

Site(将监听服务器端口与 HTTP 实现关联的对象)、Resource(在定义自定义页面时使用的便捷基类)、reactor(实现 Twisted 主循环的对象)和 endpoints 再次返回

from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor, endpoints

言归正传,这是本示例的重点。我们将定义一个资源,它将渲染一个全年的日历。它将渲染的日历年份将是请求 URL 中的年份。例如,/2009 将渲染 2009 年的日历。首先,这里有一个资源,它将渲染传递给其初始化程序的年份的日历

from calendar import calendar

class YearPage(Resource):
    def __init__(self, year):
        Resource.__init__(self)
        self.year = year

    def render_GET(self, request):
        cal = calendar(self.year)
        return (b"<!DOCTYPE html><html><head><meta charset='utf-8'>"
                b"<title></title></head><body><pre>" + cal.encode('utf-8') + b"</pre>")

非常简单 - 与 动态生成页面 中演示的第一个动态资源并没有太大区别。现在,这里有一个资源,它通过创建此 YearPage 类的适当实例来处理包含年份的 URL

class Calendar(Resource):
  def getChild(self, name, request):
      return YearPage(int(name))

通过在这里实现 getChild,我们刚刚定义了 Twisted Web 在将 URL 解析为资源时如何查找 Calendar 实例的子级。此实现将所有整数定义为 Calendar 的子级(并回避错误处理,稍后将详细介绍)。

剩下的就是使用此资源作为根创建一个 Site,然后启动反应器

root = Calendar()
factory = Site(root)
endpoint = endpoints.TCP4ServerEndpoint(reactor, 8880)
endpoint.listen(factory)
reactor.run()

就这样。任何基于资源的动态 URL 处理都将基本类似于 Calendar.getChild。以下是完整的示例代码

from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor, endpoints

from calendar import calendar


class YearPage(Resource):
    def __init__(self, year):
        Resource.__init__(self)
        self.year = year

    def render_GET(self, request):
        cal = calendar(self.year)
        return (b"<!DOCTYPE html><html><head><meta charset='utf-8'>"
                b"<title></title></head><body><pre>" + cal.encode('utf-8') + b"</pre>")


class Calendar(Resource):
  def getChild(self, name, request):
      return YearPage(int(name))

root = Calendar()
factory = Site(root)
endpoint = endpoints.TCP4ServerEndpoint(reactor, 8880)
endpoint.listen(factory)
reactor.run()