pecan的路由机制

pecan的路由机制

基于对象分发的路由机制

pecan使用对象分发的方式将某个HTTP请求(request)映射给某个控制器(controller)。

对象分发机制首先将请求路径分割成一系列的字符串,并根据这些字符串从root控制器开始依次寻找下一级控制器。可以将应用的控制器集合想象成一个对象树,这个树的每一个分支对应了一个URL路径。下面通过代码来介绍pecan的路由机制。

from pecan import expose

class BooksController(object):
    @expose()
    def index(self):
        return "Welcome to book section."

    @expose()
    def bestsellers(self):
        return "We have 5 books in the top 10."

class CatalogController(object):
    @expose()
    def index(self):
        return "Welcome to the catalog."

    books = BooksController()

class RootController(object):
    @expose()
    def index(self):
        return "Welcome to store.example.com!"

    @expose()
    def hours(self):
        return "Open 24/7 on the web."

    catalog = CatalogController()

对于上述代码,如果此时有这样一个请求:/catalog/books/bestsellers,则pecan首先将这个请求分割成:catalog, books, bestsellers。接下来,pecan将会从root控制器中寻找catalog,找到catalog对象后,pecan会继续在catalog控制器中寻找books,以此类推一直找到bestsellers。如果URL以’/‘结束,那么pecan将会查找最后一个控制器的index方法。

进一步讲,下面的这些请求路径:

└── /
    ├── /hours
    └── /catalog
         └── /catalog/books
            └── /catalog/books/bestsellers

将会路由给这些控制器方法:

└── RootController.index
    ├── RootController.hours
    └── CatalogController.index
         └── BooksController.index
            └── BooksController.bestsellers

expose()方法

你可以通过expose()方法告诉pecan一个控制器类中的哪些方法是公开可见的。如果一个控制器类的某个方法没有被expose()装饰,那么pecan不会将请求路由给它。

expose()有很多使用方法。最简单的用法就是不给它传递任何参数。在这种情况下,这个控制器返回一个代表HTML响应体的字符串。如下面的代码所示。

from pecan import expose

class RootController(object):
    @expose()
    def hello(self):
        return 'Hello World’

不过,更常见的用法是指定一个模板和名字空间,如下所示,html_template.mako是一个模板,hello()方法返回的是一个名字空间{‘msg’:’hello!'},该名字空间被用来渲染html_template.mako模板。

from pecan import expose

class RootController(object):
    @expose('html_template.mako')
    def hello(self):
        return {'msg': 'Hello!’}

html_template.mako模板内容:

<!-- html_template.mako -->
<html>
    <body>${msg}</body>
</html>

除了HTML模板,pecan也内置一个特殊的json渲染器,它将名字空间渲染进一个json文本,如下所示:

from pecan import expose

class RootController(object):
    @expose('json')
    def hello(self):
        return {'msg': 'Hello!'}

expose()方法也可以被层叠调用,这允许你根据请求内容的不同而生成不同的响应内容。

from pecan import expose

class RootController(object):
    @expose('json')
    @expose('text_template.mako', content_type='text/plain')
    @expose('html_template.mako')
    def hello(self):
        return {'msg': 'Hello!'}

从这里可以看见,我们用不同的参数分别调用了三次expose()方法。

@expose('json')

第一个调用告诉pecan当客户端请求/hello.json或者http header中包含“Accept: application/json”时,将hello()方法响应的名字空间渲染进json文本。

@expose('text_template.mako', content_type='text/plain')

 第二个调用告诉pecan当客户端请求/hello.txt或者http header中包含“Accept: text/plain”时,使用text_template.mako模板文件。

@expose('html_template.mako')

第三个调用告诉pecan当客户端请求/hello.html时,使用html_template.mako模板文件。如果客户端请求/hello,并且没有显式指明内容格式,则pecan默认使用text/html的内容格式进行响应,假设客户端想要HTML。

显式指定路径分段

偶尔,你想在路径里面显式指定分段,例如有这样一个请求:/some-path,由于python语法限制,pecan并不能将该请求的处理方法声明为some-path,即下面的代码在python中是无效的:

class RootController(object):

    @pecan.expose()
    def some-path(self):
        return dict()

 为了能绕过这种限制,pecan允许你在expose()装饰器内指定一个路径分段,如下面代码段所示:

class RootController(object):

    @pecan.expose(route='some-path')
    def some_path(self):
        return dict()

在这个例子中,pecan应用将会给/some-path/请求返回HTTP 200,但对于/some_path/请求将会返回HTTP 404。

route()方法也可以被显式的用来作为对expose()方法中route参数的代替,如下面代码段所示:

class RootController(object):

    @pecan.expose()
    def some_path(self):
        return dict()

pecan.route('some-path', RootController.some_path)

更进一步,用同样的方式,还可以利用route()方法来将请求路由给下一级控制器。

class ChildController(object):

    @pecan.expose()
    def child(self):
        return dict()

class RootController(object):
    pass

pecan.route(RootController, 'child-path', ChildController())

在这个例子中,pecan应用将会给请求/child-path/child/返回HTTP 200响应。

基于请求方法的路由

expose()方法中的generic参数可以根据请求方法对URL进行重载。在下面的例子中,同一个URL可以被两个不同的方法处理(一个用来处理HTTP GET请求,一个用来处理HTTP POST请求)。当在expose()方法的参数中指定“generic=True”后,对’/‘的GET请求,由index()方法处理,对’/‘的POST请求将会由index_POST()方法处理。

from pecan import expose


class RootController(object):

    # HTTP GET /
    @expose(generic=True, template='json')
    def index(self):
        return dict()

    # HTTP POST /
    @index.when(method='POST', template='json')
    def index_POST(self, **kw):
        uuid = create_something()
        return dict(uuid=uuid)

Pecan的路由算法

有时,标准的对象分发路由方式不足以将某个URL路由到一个控制器上。pecan提供了几种方法去使对象分发方式的路由发生短路,以便用更多的控制来处理URL,以下这些特殊的方法用来实现这个目标:_lookup(),_default(),_route()。在你的控制器上定义这些方法可以让你更加灵活的处理一个URL的全部内容或部分内容。

_lookup()方法

_lookup()提供一种方式处理一个URL的部分内容,并返回一个新的控制器用于处理URL的剩余部分。一个_lookup()方法可以提供一个或多个参数,以及URL的分片。同时_lookup()方法应该用可变的位置表示URL的剩余部分,并且在它的返回值里包含未处理的剩余URL部分。在下面的例子中,对象分发路由算法将会把remainder列表传递给该方法返回的控制器。

_lookup()除了被用来动态创建控制器以外,当没有其他任何控制器方法能够匹配一个URL且没有定义_default()方法时,_lookup()方法作为最后一个方法被调用。

from pecan import expose, abort
from somelib import get_student_by_name

class StudentController(object):
    def __init__(self, student):
        self.student = student

    @expose()
    def name(self):
        return self.student.name

class RootController(object):
    @expose()
    def _lookup(self, primary_key, *remainder):
        student = get_student_by_primary_key(primary_key)
        if student:
            return StudentController(student), remainder
        else:
            abort(404)

对'/8/name’的GET请求将会返回primary_key等于8的学生的名字。

_default()方法

对于标准的对象分发路由机制,当没有其他任何控制器方法能够匹配一个URL时, _default()方法作为最后一个方法被调用。

from pecan import expose

class RootController(object):
    @expose()
    def english(self):
        return 'hello'

    @expose()
    def french(self):
        return 'bonjour'

    @expose()
    def _default(self):
        return 'I cannot say hello in that language'

在上面的例子中,对/spanish的请求将会路由到RootController._default()方法。

_route()方法

_route()方法允许一个控制器完全覆盖pecan的路由机制。pecan它本身也使用_route()方法去实现它的RestController。如果你想在pecan之上定义一套替代的路由机制,那么定义一个包含_route()方法的基控制器将会使你完全掌控请求的路由。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值