tornado 路由系统----扩展(include)

 

补充: 如果最后要求所有没有匹配到的路由跳转到某一页或handler去, 怎么做

(   r'/.*', ShowAdminHandler), 完美

 

在Tornado中实现Django分层路由

看了几个 Tornado 的 demo 发现都是一个py搞定所有,这样做做为例子来讲确实很直观,但如果在大型项目中这样做肯定不现实,所以博主考虑如何制定合理的 Tornado 目录。

我认为 Django 的目录有很多可取之处,然而在进行分层的时候就遇到了第一个问题:路由分层。看了 Tornado 的源码和文档发现 Tornado 官方并没有提供分层路由的实现,于是接着搜索 gayhub 😆, 发现有个“tornado-routes” 的项目。经过阅读发现此项目确实丰富了 Tornado 的路由,也考虑到了分层路由,但其使用的是直接在类中添加修饰器的方式做路由,这和 Django 分层路由大相径庭,同时感觉它的实现方式也略为繁琐,因此我就排除了这个方案。之后又浏览了一些相关的 repo ,并没有再找到考虑分层路由的包。既然没人造这个轮子博主自己造好啦。

首先要做的就是了解 Tornado 是如何处理路由的。 Tornado 的启动文件一般是这样的:

app = tornado.web.Application(
    [
        (r"/", MainHandler),
        (r"/a/message/new", MessageNewHandler),
        (r"/a/message/updates", MessageUpdatesHandler),
        ]
    )
app.listen(options.port)
tornado.ioloop.IOLoop.current().start()

可以直观的看到路由都在 tornado.web.Application() 的第一个 list 里,所以直接去看 Tornado 源码里 tornado.web.Application 的实现:

def __init__(self, handlers=None, default_host="", transforms=None,
                 **settings):
        ...
        if handlers:
            self.add_handlers(".*$", handlers)
        ...

从初始化方法中我们知道了路由 list 在 Application 里叫 handlers, 其中self.add_handlers() 就是 Tornado 处理路由的关键。

然后来看add_handlers(self, host_pattern, host_handlers) 方法:

def add_handlers(self, host_pattern, host_handlers):
    """Appends the given handlers to our handler list.
    Host patterns are processed sequentially in the order they were
    added. All matching patterns will be considered.
    """
    if not host_pattern.endswith("$"):
        host_pattern += "$"
    handlers = []
    # The handlers with the wildcard host_pattern are a special
    # case - they're added in the constructor but should have lower
    # precedence than the more-precise handlers added later.
    # If a wildcard handler group exists, it should always be last
    # in the list, so insert new groups just before it.
    if self.handlers and self.handlers[-1][0].pattern == '.*$':
        self.handlers.insert(-1, (re.compile(host_pattern), handlers))
    else:
        self.handlers.append((re.compile(host_pattern), handlers))
    for spec in host_handlers:
        if isinstance(spec, (tuple, list)):
            assert len(spec) in (2, 3, 4)
            spec = URLSpec(*spec)
        handlers.append(spec)
        if spec.name:
            if spec.name in self.named_handlers:
                app_log.warning(
                    "Multiple handlers named %s; replacing previous value",
                    spec.name)
            self.named_handlers[spec.name] = spec

可以看到此方法接受的是一个 tuple 的 list 并通过处理返回一个 URLSpec() 的 list, 那么其实只要把分层路由信息统一成一个 tuple 的 list 传给 Application就可以实现分层路由的实现。

为了实现统一分层路由需要写两个方法: 一个是 include(url_module) 引入子层路由信息统一输出,另一个 url_wrapper(urls) 则是将分层、不分层信息统一格式化成一个 tuple 的 list, 具体实现:

import tornado.httpserver
import tornado.ioloop
import tornado.web
from url_router import include, url_wrapper
from importlib import import_module

def include(module):
    res = import_module(module)
    urls = getattr(res, 'urls', res)
    return urls
def url_wrapper(urls):
    wrapper_list = []
    for url in urls:
        path, handles = url
        if isinstance(handles, (tuple, list)):
            for handle in handles:
                pattern, handle_class = handle
                wrap = ('{0}{1}'.format(path, pattern), handle_class)
                wrapper_list.append(wrap)
        else:
            wrapper_list.append((path, handles))
    return wrapper_list


application = tornado.web.Application(url_wrapper([
    (r"/test/", include('test.urls')),
    (r"/other", XXXHandle),
]))
if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

 

#test/urls.py
 coding: utf-8
from __future__ import unicode_literals
from test.views import TestWriteHandle, TestHandle
urls = [
    (r'write', TestWriteHandle),
    (r'', TestHandle),
]

然后运行 Tornado 服务器,分别打开 http://localhost:8888/test/write 和 http://localhost:8888/other 测试可用性。

一个简单的 Django 分层路由就可以在 Tornado 中使用啦。

 

原文地址:https://www.rapospectre.com/blog/13

 

posted @ 2016-12-09 14:22  我当道士那儿些年  阅读(2376)  评论(0编辑  收藏  举报