zoukankan      html  css  js  c++  java
  • Pecan控制器和路由系统

    Pecan路由采用的是对象分发机制,将HTTP请求分发到控制器,然后到控制器里定义的方法。

    对象分发机制将请求路径进行切割,根据请求路径从root控制器开始,按次序寻找路径对应的控制器及方法。

    一、控制器和路由实例

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

    1, 访问/时,会由RootController类的index方法进行响应;

    2, 访问/hours或者/hours/时,会由RootController类的hours方法进行响应;

    3, 访问/catalog时,首先会通过RootController找到其catalog属性,也就是一个CatalogController实例,然后寻找CatalogController类的index方法进行响应;

    4, 访问/catalog/books时,首先会通过RootController找到其catalog属性,也就是一个CatalogController实例,然后寻找CatalogController类的books属性,也就是一个BookController实例,使用其index方法进行响应;

    5, 访问/catalog/books/bestsellers时,首先会通过RootController找到其catalog属性,也就是一个CatalogController实例,然后寻找CatalogController类的books属性,也就是一个BookController实例,使用其bestseller方法进行响应.

    二、expose 暴露控制器方法

    expose告诉Pecan类中的哪些方法是公开可见的 如果一个方法没有用修饰expose(),Pecan永远不会将请求路由到它。

    pecan默认采用expose进行路由绑定,需要路由控制器类的方法都要经过expose装饰器的装饰,pecan就可以使HTTP请求找到对应的方法。

    不同的使用方法会有不同的效果,如下:

    2.1 expose()

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

    被装饰的方法需要返回一个字符串,表示HTML响应的body。

    2.2 @expose(html_template_name)

    from pecan import expose
     
    class RootController(object):
        @expose('html_template.mako')
        def hello(self):
            return {'msg': 'Hello!’}
    <!-- html_template.mako -->
    <html>
        <body>${msg}</body>
    </html>

    被装饰的方法返回一个字典,字典的key可以在html模板中使用${key}的方式引用。

    2.3 @expose(route='some-path')

    例如有这样一个请求:/some-path,由于python语法限制,pecan并不能将该请求的处理方法声明为some-path。使用@expose(route='some-path'),被装饰方法将响应/some-path请求。

    class RootController(object):
     
        @expose(route='some-path')
        def some_path(self):
            return dict()

    注意:尽量不使用dict(),使用不当,HTTP状态码将是204,及服务器没有返回任何内容错误。

    另一种方式:pecan.route()

    class RootController(object):
     
        @expose()
        def some_path(self):
            return dict()
     
    pecan.route('some-path', RootController.some_path)

    延伸:利用route()方法来将请求路由给下一级控制器

    class ChildController(object):
     
        @expose()
        def child(self):
            return dict()
     
    class RootController(object):
        pass
     
    pecan.route(RootController, 'child-path', ChildController())

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

    2.4 @expose(generic=True)

    expose()方法中的generic参数可以根据请求方法对URL进行重载,即一个url路径可以被两个不同的方法处理。

    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)

    对于"/"的GET请求,由index()方法处理;对于"/"的POST请求,由index_POST方法处理。

    2.5 @expose()叠加用法

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

    叠加使用后一个hello方法可以响应三种格式的请求(application/json, text/plain, text/html)。

    当客户端请求/hello.json或者http header中包含“Accept: application/json”时,将hello()方法响应的名字空间渲染进json文本,及@expose('json')用法;

    当客户端请求/hello.txt或者http header中包含“Accept: text/plain”时,使用text_template.mako模板文件响应,即@expose('text_template.mako', content_type='text/plain')用法;

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

     2.6 _lookup()

    _lookup方法是最后尝试的方法,只有没有控制器可以响应请求的URL,而且最后找到的控制器没有定义_default方法时,采用_lookup。

    此方法返回一个新的控制器用于控制url的剩余部分,如下代码:

    def get_student_by_primary_key(num):
        a = ["xiao_ming", "xiao_li"]
        num = int(num) if type(num) == int and len(a) > int(num) else 0
        return a[num]
    
    
    class Addr(object):
        @expose()
        def index(self):
            return "addr"
    
    
    class StudentController(object):
        def __init__(self, student):
            self.student = student
    
        @expose()
        def name(self):
            return self.student
    
        addr = Addr()
    
    
    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:
                return "404"

    例如"/1/name"路径,将走_lookup()方法,返回 StudentController(student), remainder;

    此时,StudentController(student) 是一个新的控制器,而remainder是url的剩余部分,即 name;

    StudentController() 控制器将找到def name(self) 进而响应请求。

    同理,对于"/100/addr",也走_lookup()方法,返回 StudentController(student), remainder;

    此时,StudentController(student) 是一个新的控制器,而remainder是url的剩余部分,即 addr;

    找到addr = Addr(),进而得到响应。

    2.7 _default()

     对于标准的对象路由分发机制,当没有任何控制器可以处理url是,_default将要作为最后一个方法被调度。

    from functools import wraps
    
    
    def happy_expose(f=None, **kw):
        if f is None:
            def inner_expose(func):
                return happy_expose(func, **kw)
            return inner_expose
        else:
            @wraps(f)
            @expose(**kw)
            def _expose(*args, **kwargs):
                return f(*args, **kwargs)
            return _expose
    class RootController(object):
    
        @expose()
        def hours(self):
            return "Open 24/7 on the web."
    
        @happy_expose
        def _default(self, *remainder):
            return 'Hello World from root default'

    _default方法是最后被调用的。

    结束!

  • 相关阅读:
    (二分查找 拓展) leetcode 69. Sqrt(x)
    (二分查找 拓展) leetcode 162. Find Peak Element && lintcode 75. Find Peak Element
    (链表) lintcode 219. Insert Node in Sorted Linked List
    (二分查找 拓展) leetcode 34. Find First and Last Position of Element in Sorted Array && lintcode 61. Search for a Range
    (最短路 Floyd) P2910 [USACO08OPEN]寻宝之路Clear And Present Danger 洛谷
    (字符串 数组 递归 双指针) leetcode 344. Reverse String
    (二叉树 DFS 递归) leetcode 112. Path Sum
    (二叉树 DFS 递归) leetcode 101. Symmetric Tree
    (二叉树 递归) leetcode 144. Binary Tree Preorder Traversal
    (二叉树 递归 DFS) leetcode 100. Same Tree
  • 原文地址:https://www.cnblogs.com/aaronthon/p/14832494.html
Copyright © 2011-2022 走看看