URL 路由 — Werkzeug 文档
URL路由
当涉及到组合多个控制器或视图函数时(不管你想如何调用它们),你需要一个调度程序。 一种简单的方法是在 PATH_INFO
上应用正则表达式测试并调用返回值的注册回调函数。
Werkzeug 提供了一个更强大的系统,类似于 Routes。 本页提到的所有对象必须从werkzeug.routing导入,而不是从werkzeug
导入!
快速入门
这是一个简单的示例,它可以是博客的 URL 定义:
from werkzeug.routing import Map, Rule, NotFound, RequestRedirect
url_map = Map([
Rule('/', endpoint='blog/index'),
Rule('/<int:year>/', endpoint='blog/archive'),
Rule('/<int:year>/<int:month>/', endpoint='blog/archive'),
Rule('/<int:year>/<int:month>/<int:day>/', endpoint='blog/archive'),
Rule('/<int:year>/<int:month>/<int:day>/<slug>',
endpoint='blog/show_post'),
Rule('/about', endpoint='blog/about_me'),
Rule('/feeds/', endpoint='blog/feeds'),
Rule('/feeds/<feed_name>.rss', endpoint='blog/show_feed')
])
def application(environ, start_response):
urls = url_map.bind_to_environ(environ)
try:
endpoint, args = urls.match()
except HTTPException, e:
return e(environ, start_response)
start_response('200 OK', [('Content-Type', 'text/plain')])
return [f'Rule points to {endpoint!r} with arguments {args!r}']
那有什么作用呢? 首先我们创建一个新的 Map
来存储一堆 URL 规则。 然后我们向它传递一个 Rule
对象列表。
每个 Rule
对象都使用表示规则的字符串和端点进行实例化,端点将是规则所代表的视图的别名。 多个规则可以具有相同的端点,但应该具有不同的参数以允许 URL 构造。
URL 规则的格式很简单,但在下面详细解释。
在 WSGI 应用程序中,我们将 url_map 绑定到当前请求,它将返回一个新的 MapAdapter
。 然后可以使用这个 url_map 适配器来匹配或构建当前请求的域。
然后,MapAdapter.match()
方法可以返回 (endpoint, args)
形式的元组或引发三个异常 NotFound
、MethodNotAllowed
或 RequestRedirect
之一]。 有关这些异常的更多详细信息,请查看 MapAdapter.match()
方法的文档。
规则格式
规则字符串是带有变量部分占位符的 URL 路径,格式为 <converter(arguments):name>
。 converter
和 arguments
(带括号)是可选的。 如果没有给出转换器,则使用 default
转换器(默认为 string
)。 下面讨论可用的转换器。
以斜线结尾的规则是“分支”,其他的是“叶子”。 如果 strict_slashes
启用(默认),访问没有斜杠的分支 URL 将重定向到附加斜杠的 URL。
许多 HTTP 服务器在接收请求时将连续的斜杠合并为一个。 如果启用 merge_slashes
(默认),规则将在匹配和构建时合并非可变部分中的斜线。 访问带有连续斜杠的 URL 将重定向到合并了斜杠的 URL。 如果您想为 Rule
或 Map
禁用 merge_slashes
,您还需要适当地配置您的网络服务器。
内置转换器
常见类型的 URL 变量的转换器是内置的。 可用的转换器可以通过 Map.converters
覆盖或扩展。
地图、规则和适配器
规则工厂
规则模板
自定义转换器
您可以添加自定义转换器,以添加内置转换器未提供的行为。 要制作自定义转换器,子类 BaseConverter
然后将新类传递给 Map
converters
参数,或将其添加到 url_map.converters
。
转换器应该有一个 regex
属性和一个匹配的正则表达式。 如果转换器可以在 URL 规则中接受参数,则它应该在其 __init__
方法中接受它们。
它可以实现 to_python
方法将匹配的字符串转换为其他对象。 这也可以进行 regex
属性无法实现的额外验证,在这种情况下应该引发 werkzeug.routing.ValidationError
。 引发任何其他错误将导致 500 错误。
它可以在构建 URL 时实现 to_url
方法将 Python 对象转换为字符串。 此处引发的任何错误都将转换为 werkzeug.routing.BuildError
并最终导致 500 错误。
此示例实现了一个 BooleanConverter
,它将匹配字符串 "yes"
、"no"
和 "maybe"
,返回 "maybe"
的随机值。
from random import randrange
from werkzeug.routing import BaseConverter, ValidationError
class BooleanConverter(BaseConverter):
regex = r"(?:yes|no|maybe)"
def __init__(self, url_map, maybe=False):
super().__init__(url_map)
self.maybe = maybe
def to_python(self, value):
if value == "maybe":
if self.maybe:
return not randrange(2)
raise ValidationError
return value == 'yes'
def to_url(self, value):
return "yes" if value else "no"
from werkzeug.routing import Map, Rule
url_map = Map([
Rule("/vote/<bool:werkzeug_rocks>", endpoint="vote"),
Rule("/guess/<bool(maybe=True):foo>", endpoint="guess")
], converters={'bool': BooleanConverter})
如果要更改默认转换器,请将不同的转换器分配给 "default"
键。
主机匹配
0.7 版中的新功能。
从 Werkzeug 0.7 开始,还可以对整个主机名进行匹配,而不仅仅是对子域进行匹配。 要启用此功能,您需要将 host_matching=True
传递给 Map
构造函数并向所有路由提供 host 参数:
url_map = Map([
Rule('/', endpoint='www_index', host='www.example.com'),
Rule('/', endpoint='help_index', host='help.example.com')
], host_matching=True)
可变部分当然也可以在主机部分:
url_map = Map([
Rule('/', endpoint='www_index', host='www.example.com'),
Rule('/', endpoint='user_index', host='<user>.example.com')
], host_matching=True)
网络套接字
1.0 版中的新功能。
如果 Rule
是用 websocket=True
创建的,它只会在 Map
绑定到 ws
的 url_scheme
的请求时匹配或 wss
。
笔记
除了路由之外,Werkzeug 没有进一步的 WebSocket 支持。 此功能主要用于 ASGI 项目。
url_map = Map([
Rule("/ws", endpoint="comm", websocket=True),
])
adapter = map.bind("example.org", "/ws", url_scheme="ws")
assert adapter.match() == ("comm", {})
如果唯一匹配是 WebSocket 规则并且绑定是 HTTP(或者唯一匹配是 HTTP 并且绑定是 WebSocket),则会引发 WebsocketMismatch
(派生自 BadRequest
)异常。
由于 WebSocket URL 有不同的方案,规则总是用方案和主机构建,force_external=True
是隐含的。
url = adapter.build("comm")
assert url == "ws://example.org/ws"