Sanic的核心路由组件
项目描述
Sanic路由
背景
从v21.3版本开始,Sanic利用这种新的AST-style路由器在两个用例中进行了使用
- 路由路径;
- 路由信号。
因此,此软件包包含一个BaseRouter
,需要对其进行子类化才能用于其特定需求。
大多数Sanic用户不需要关心这里的细节。
基本示例
简单实现
import logging
from sanic_routing import BaseRouter
logging.basicConfig(level=logging.DEBUG)
class Router(BaseRouter):
def get(self, path, *args, **kwargs):
return self.resolve(path, *args, **kwargs)
router = Router()
router.add("/<foo>", lambda: ...)
router.finalize()
router.tree.display()
logging.info(router.find_route_src)
route, handler, params = router.get("/matchme", method="BASE", extra=None)
上面的代码段使用router.tree.display()
显示路由器如何决定将路由安排成树形结构。在这个简单示例中
<Node: level=0>
<Node: part=__dynamic__:str, level=1, groups=[<RouteGroup: path=<foo:str> len=1>], dynamic=True>
我们可以看到路由器为我们生成的代码。它作为字符串在router.find_route_src
中可用。
def find_route(path, method, router, basket, extra):
parts = tuple(path[1:].split(router.delimiter))
num = len(parts)
# node=1 // part=__dynamic__:str
if num == 1: # CHECK 1
try:
basket['__matches__'][0] = str(parts[0])
except ValueError:
pass
else:
# Return 1
return router.dynamic_routes[('<__dynamic__:str>',)][0], basket
raise NotFound
FYI: 如果你使用的是Python 3.9,你可以在router.find_route_src_compiled
中看到编译后的源代码表示。
它在做什么?
因此,在一般实现中,您需要
- 定义一个带有
get
方法的路由器; - 添加一个或多个路由;
- 最终化路由器(
router.finalize()
); - 调用路由器的
get
方法。
注意:如果您不希望将源代码编译成可执行形式,则可以调用router.finalize(False)
。如果您只想查看生成的输出,这将很有用。
每次您调用router.add
时,您都会创建一个(1)新的Route
实例。即使该路由使用了多个方法,它也只生成一个实例。如果您添加了一个具有类似路径结构(但可能有不同方法)的另一个Route
,它们将组合成一个RouteGroup
。还值得注意,RouteGroup
是在第一次调用add()
时创建的,但后续类似的路由将重用现有的分组实例。
当调用 finalize()
方法时,它会将定义的路由组按照层次结构排列成“节点”。单个节点是一个路径段。一个 Node
实例可以有一个或多个 RouteGroup
,其中 Node
是该路径的终止点。
也许一个例子更容易理解
router.add("/path/to/<foo>", lambda: ...)
router.add("/path/to/<foo:int>", lambda: ...)
router.add("/path/to/different/<foo>", lambda: ...)
router.add("/path/to/different/<foo>", lambda: ..., methods=["one", "two"])
生成的 RouteGroup
实例(3个)
<RouteGroup: path=path/to/<foo:str> len=1>
<RouteGroup: path=path/to/<foo:int> len=1>
<RouteGroup: path=path/to/different/<foo:str> len=2>
生成的 Route
实例(4个)
<Route: path=path/to/<foo:str>>
<Route: path=path/to/<foo:int>>
<Route: path=path/to/different/<foo:str>>
<Route: path=path/to/different/<foo:str>>
节点树
<Node: level=0>
<Node: part=path, level=1>
<Node: part=to, level=2>
<Node: part=different, level=3>
<Node: part=__dynamic__:str, level=4, groups=[<RouteGroup: path=path/to/different/<foo:str> len=2>], dynamic=True>
<Node: part=__dynamic__:int, level=3, groups=[<RouteGroup: path=path/to/<foo:int> len=1>], dynamic=True>
<Node: part=__dynamic__:str, level=3, groups=[<RouteGroup: path=path/to/<foo:str> len=1>], dynamic=True>
以及生成的源代码
def find_route(path, method, router, basket, extra):
parts = tuple(path[1:].split(router.delimiter))
num = len(parts)
# node=1 // part=path
if num > 1: # CHECK 1
if parts[0] == "path": # CHECK 4
# node=1.1 // part=to
if num > 2: # CHECK 1
if parts[1] == "to": # CHECK 4
# node=1.1.1 // part=different
if num > 3: # CHECK 1
if parts[2] == "different": # CHECK 4
# node=1.1.1.1 // part=__dynamic__:str
if num == 4: # CHECK 1
try:
basket['__matches__'][3] = str(parts[3])
except ValueError:
pass
else:
if method in frozenset({'one', 'two'}):
route_idx = 0
elif method in frozenset({'BASE'}):
route_idx = 1
else:
raise NoMethod
# Return 1.1.1.1
return router.dynamic_routes[('path', 'to', 'different', '<__dynamic__:str>')][route_idx], basket
# node=1.1.2 // part=__dynamic__:int
if num >= 3: # CHECK 1
try:
basket['__matches__'][2] = int(parts[2])
except ValueError:
pass
else:
if num == 3: # CHECK 5
# Return 1.1.2
return router.dynamic_routes[('path', 'to', '<__dynamic__:int>')][0], basket
# node=1.1.3 // part=__dynamic__:str
if num >= 3: # CHECK 1
try:
basket['__matches__'][2] = str(parts[2])
except ValueError:
pass
else:
if num == 3: # CHECK 5
# Return 1.1.3
return router.dynamic_routes[('path', 'to', '<__dynamic__:str>')][0], basket
raise NotFound
特殊情况
上面的例子只显示了包含动态路径段的路由(例如:<foo>
)。但还有一些其他的使用案例,处理方式不同
- 完全静态路径 - 这些是没有参数的路径(例如:
/user/login
)。这些基本上是与键/值存储进行匹配。 - 正则表达式路径 - 如果一个路由有单个正则表达式匹配,则整个路由将通过正则表达式进行匹配。通常,这发生在行内,与上面例子中的情况不太一样。
- 特殊正则表达式路径 - 路由器提供了一个特殊的
path
类型(例如:<foo:path>
),它可以匹配扩展的分隔符。这也适用于使用路径分隔符的任何正则表达式。由于它们长度未知,因此不能在常规情况下进行匹配。
项目详情
下载文件
下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源代码发行版
构建发行版
sanic-routing-23.12.0.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 1dcadc62c443e48c852392dba03603f9862b6197fc4cba5bbefeb1ace0848b04 |
|
MD5 | e2ff8482fa88d053976af5b401ac32cc |
|
BLAKE2b-256 | d15c2a7edd14fbccca3719a8d680951d4b25f986752c781c61ccf156a6d1ebff |
sanic_routing-23.12.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 1558a72afcb9046ed3134a5edae02fc1552cff08f0fff2e8d5de0877ea43ed73 |
|
MD5 | cbd8fc9ae85737849c674aa5814b3356 |
|
BLAKE2b-256 | cfe33425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5 |