Pecan 框架学习笔记

Pecan 是一个 WSGI(Web Server Gateway Interface) 对象调度 web 框架,具有架构设计精妙、响应快速,依赖较少的特点。在 OpenStack API 框架中使用较多。


一、Pecan 工程的创建和运行

1. 安装 Pecan

使用 pip 安装 pecan:

pip install pecan

2. 创建第一个 Pecan 应用

创建虚拟环境并激活:

virtualenv pecan-env
cd pecan-env
source bin/activate
pecan create pecandemo
cd pecandemo

3. 运行 Pecan 工程

pecan serve config.py

二、RootController 模版代码分析

RootController 是 Pecan 应用程序根路径对应的控制器。新建的 Pecan 工程中,pecandemo.contronllers.root.py 中有如下模版代码:

class RootController(object):
@expose(generic=True, template='index.html')
def index(self):
return dict()
@index.when(method='POST')
def index_post(self, q):
redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q)
@expose('error.html')
def error(self, status):
try:
status = int(status)
except ValueError: # pragma: no cover
status = 500
message = getattr(status_map.get(status), 'explanation', '')
return dict(status=status, message=message)

逐个方法看一下:

1. index() 方法

@expose(generic=True, template='index.html')
def index(self):
return dict()

任何到达应用程序根目录(/)的 HTTP GET 都将被路由到此方法。index()  方法返回一个字典。

趁此,说一下 pecan.expose
pecan.expose 可以标记 controller 方法,使得一个方法可以通过 HTTP 访问,主要形参有:

  • generic:boolean 值。当为 True 时,相同的路径会因 HTTP 方法的不同路由到相应的方法。
  • template:模板。
  • route:指定路径段的名字,默认是函数名。

Pecan 默认采用 expose 进行路由绑定,可以使 HTTP 请求找到对应的方法。如果一个方法没有用 expose 修饰,Pecan 不会将请求路由到它。
不同的使用方法有不同的效果,举例:

  • expose()
class RootController(object):
@expose()
def hello(self):
return "Hello World!"

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

  • @expose("html_template_name")
class RootController(object):
@expose("html_demo.html")
def say_hello(self):
return {"say": "Hello, pecan!"}

被装饰的方法返回一个 Python 字典,该字典可以在 HTML 模版中使用 ${key} 的方式引用,如 html_demo.html 如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
${say} <br>
</body>
</html>

运行起来使用浏览器通过 URL(实例:http://127.0.0.1:8080/say_hello)访问如下图:
![[Hello, pecan!.png|180]]

  • expose(route="certain-name")

默认在请求某个方法时是用方法名,例如上面就用的 http://.../say_hello。但有时候会有将请求改为类似于 /certain-name 的需求,由于 Python 语法限制,方法并不能命名为 certain-name ,这时使用 @expose(route="certain-name"),被装饰方法将响应 /certain-name 请求。

  • @expeose(generic=True)

expose() 方法中的 generic 参数当为 True 时,可以根据请求方法对 URL 进行重载,即一个 URL 路径可以被两个不同的方法处理,相同的路径会因 HTTP 方法的不同路由到相应的方法。

  • expose() 叠加使用
class RootController(object):
@expose("json")
@expose("html_demo.html", content_type="text/plain")
@expose("html_demo.html")
def say_hello(self):
return {"say": "Hello, pecan!"}

叠加使用后一个 say_hello 方法可以响应三种格式的请求(application/jsontext/plaintex t/html)。

@expose("json")

当客户端请求  /say_hello.json  或是 http header 中否存在  Accept: application/json 时,使用 JSON 序列化响应。
访问 http://127.0.0.1:8080/say_hello.json
![[Pasted image 20230713113015.png|180]]

@expose("html_demo.html", content_type="text/plain")

当客户端请求 /say_hello.txt 或者 http header 中存在 Accept: text/plain 时,使用 html_demo.html 模板文件响应。
访问 http://127.0.0.1:8080/say_hello.txt
![[Pasted image 20230713113146.png|180]]

@expose("html_demo.html")

当客户端请求  /say_hello.html  时使用  html_demo.html  模板文件。如果客户端请求  /say_hello 并且没有显式指明内容类型,pecan 将默认使用  text/html  内容类型进行相应,假定客户端需要 HTML。

2. index_post() 方法

@index.when(method='POST')
def index_post(self, q):
redirect('https://pecan.readthedocs.io/en/latest/search.html?q=%s' % q)

@index.when(method='POST') 与刚才 index() 方法上的 generic=True 配合实现任何到应用程序根目录的 HTTP POST 都将路由到该方法。
index_post()  方法接收一个 HTTP POST 参数(q)。

3. error() 方法

@expose('error.html')
def error(self, status):
try:
status = int(status)
except ValueError: # pragma: no cover
status = 500
message = getattr(status_map.get(status), 'explanation', '')
return dict(status=status, message=message)

该方法允许应用程序显示某些 HTTP 错误(404 等)的自定义页面。


三、路由策略

Pecan 使用称为对象分发(object-dispatch)的路由策略(routing strategy)将 HTTP 请求映射到控制器,然后将方法回调。对象分发首先将路径拆分为组件列表,然后从根控制器开始遍历对象路径。您可以将应用程序的控制器想象成一棵对象树(对象树的分支直接映射到 URL 路径)。

网上有个比较典型的小例子:

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

路由路径:

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

请求示例:

  1. http://127.0.0.1:8080/catalog/ :
    ![[Pasted image 20230713103658.png|200]]

  2. http://127.0.0.1:8080/catalog/books/bestsellers
    ![[iShot_2023-07-13_10.33.43.png|200]]

posted @   OXYGEN1  阅读(87)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示