Bottle 请求路由完全指南:规则语法、通配符过滤器与显式配置实战
后端Web框架【免费下载链接】bottlebottle.py is a fast and simple micro-framework for python web-applications.项目地址https://gitcode.com/gh_mirrors/bo/bottle点击查看免费下载Bottle 是一个仅依赖 Python 标准库的微型 Web 框架其内部的路由引擎Router负责将每一个 HTTP 请求精确地映射到对应的回调函数。本文基于 docs/routing.rst 展开深入讲解路由规则语法静态路由与动态路由、标准与自定义通配符过滤器、旧版语法的兼容方式以及显式路由配置方法。读完本文你将能够写出清晰、无歧义、可维护的路由规则并能在需要时自定义过滤器或绕过装饰器语法直接控制路由注册时机。路由引擎的工作方式Bottle 的路由核心实现在 bottle.py 的Router类中bottle.py#L261-L464。从源码结构看Router内部维护了多套数据结构self.static静态路由的查找表以 HTTP 方法为键、路径为索引用于 O(1) 命中静态路径self.dyna_routes与self.dyna_regexes动态路由的有序列表与合并后的正则表达式集合self.filters内置过滤器的字典self.builder用于反向构建 URL 的数据结构。Router.match(environ)bottle.py#L430-L464是每一次请求的必经之路它根据 WSGI 环境中的REQUEST_METHOD与PATH_INFO查找目标。查找失败时如果存在同路径的其他 HTTP 方法会抛出带Allow响应头的HTTPError(405)否则抛出HTTPError(404)。这解释了为什么对错误方法或不存在路径的请求Bottle 会返回标准的 405/404 状态码。规则语法静态路由与动态路由Router将路由规则区分为两种基本类型bottle.py#L261-L271静态路由如/contact不含任何通配符只匹配完全相同的路径动态路由如/hello/name包含一个或多个通配符可以同时匹配多条 URL。通配符的基本形式最简单的通配符由一对尖括号包裹的名字组成例如name。通配符名字需要满足以下约束自 Bottle 0.10 起的新语法见docs/routing.rst的versionchanged说明对于同一条路由必须唯一必须构成合法的 Python 标识符以字母开头、由字母和数字组成。这是因为每个通配符最终会以关键字参数的形式传给请求回调。例如/hello/name匹配/hello/alice时回调将收到namealice。通配符的匹配边界每个通配符默认匹配一个或多个字符但在第一个斜杠/处停止等价于正则表达式[^/]正是Router.default_pattern的值见bottle.py#L273。这保证了每个通配符只消费一个路径段从而使含多个通配符的路由保持无歧义。文档给出了规则/action/item的完整匹配结果路径结果/save/123{action: save, item: 123}/save/123/不匹配/save/不匹配//123不匹配这一点同样被测试用例覆盖test/test_router.py中的testNewSyntax验证了test无头test/、无尾/test、中置/test/和全通配test等各种位置形式并断言//no/m/at/ch/这类路径抛出HTTPError。转义特殊字符在某些场景下你需要字面使用旧语法的特殊字符例如冒号:。可以用反斜杠\进行转义规则/action/item:id会触发旧语法解析而/action/item\:id则按新语法正常工作。从源码看Router.rule_syntax正则bottle.py#L303-L306显式匹配奇数个反斜杠视为转义通配符_itertokensbottle.py#L308-L327在遇到奇数个\时会将通配符当作普通前缀文本处理。因此要匹配字面、:等字符只需在它们前面加一个反斜杠。通配符过滤器约束与转换过滤器Bottle 0.10 引入用于定义更具体的通配符或在匹配值传给回调之前对其进行类型转换。过滤通配符的声明形式为name:filter或name:filter:config其中 config 部分的语法取决于所用过滤器。内置过滤器Router.__init__中预置了四个过滤器bottle.py#L289-L295对应实现如下过滤器源码实现行为说明:int(r-?\d, int, ...)匹配带符号的数字并转换为整数:float(r-?[\d.], float, ...)类似:int但用于十进制小数:path(r.?, None, None)非贪婪匹配包括斜杠在内的所有字符可跨多个路径段:re[:exp](_re_flatten(conf or [^/]), None, None)在 config 中指定自定义正则匹配值不做类型转换每个过滤器本质上是一个三元组正则表达式字符串、将 URL 片段转换为 Python 值的可调用对象、以及做反向转换的可调用对象。int/float的第三个元素lambda x: str(int(x))就是反向转换器它让Router.build()能根据参数反向生成 URL。实战示例同时可见于 docs/tutorial.rst 的动态路由章节from bottle import route, static_file # :int —— 回调收到的是真正的整数 route(/object/id:int) def show_object(id): assert isinstance(id, int) # :re[:exp] —— 自定义正则约束 route(/show/name:re:[a-z]) def show_name(name): assert name.isalpha() # :path —— 匹配包含斜杠的多段路径常用于静态文件 route(/static/path:path) def serve_static(path): return static_file(path, root/path/to/static)注意:path的正则是.?非贪婪因此它只会消费到能匹配的最小范围如果你在:path之后再放置其他通配符后面的通配符仍有机会匹配剩余路径段。test/test_router.py的testPathFilter验证了/a/b能被/id:path/:f解析为ida, fb。自定义过滤器add_filter当内置过滤器不够用时可以注册自己的过滤器。只需编写一个以 config 字符串为唯一参数、返回三元组正则字符串、正向转换函数、反向转换函数的函数然后调用app.router.add_filter(name, func)源码见bottle.py#L297-L301import re from bottle import Bottle app Bottle() def list_filter(config): 匹配一个逗号分隔的数字列表。 delimiter config or , regexp r\d(%s\d)* % re.escape(delimiter) def to_python(match): return map(int, match.split(delimiter)) def to_url(numbers): return delimiter.join(map(str, numbers)) return regexp, to_python, to_url app.router.add_filter(list, list_filter) app.route(/follow/ids:list) def follow_users(ids): for id in ids: ...使用说明add_filter的第一个参数是过滤器名第二个是工厂函数工厂函数会在路由注册时被调用并传入:filter:config中的 config 部分返回的regexp是纯字符串捕获组会被自动改写为命名组或非捕获组见_re_flattenbottle.py#L252-L258to_python负责把匹配片段转成 Python 值to_url用于Router.build()反向生成 URL在 Python 3 中map(int, ...)返回迭代器若后续需要多次遍历或直接调试可改为list(map(int, ...))若过滤器在转换时抛出ValueErrorRouter.add内部会捕获并转为HTTPError(400, Path has wrong format.)bottle.py#L370-L379testValueErrorInFilter与testIntFilter均验证了这一行为。旧语法与向后兼容新规则语法在Bottle 0.10中引入用于简化常见场景但旧语法依然可用网上仍能见到大量使用旧语法的示例代码。新旧语法对照如下来自docs/routing.rst旧语法新语法:namename:name#regexp#name:re:regexp:#regexp#:re:regexp:##:re建议新项目尽量使用新语法。旧语法目前尚未被标记废弃但按文档说明最终会被废弃。事实上源码_itertokensbottle.py#L313-L316在解析到旧语法时已经会发出depr弃用警告提示信息为 Use of old route syntax. Use instead of :name in routes.test/test_router.py的testBasic也在忽略警告的前提下验证了旧语法的各种位置组合仍然可用。另外两种语法都支持匿名通配符/anon/或/anonfilter/:int这类没有名字的通配符会自动获得anon0、anon1…… 这样的生成名见Router.addbottle.py#L343-L345并在传给回调前从参数字典中删除bottle.py#L377-L378。测试testAnonWildcard覆盖了该行为。显式路由配置装饰器之外的另一条路route既可以作为装饰器使用也可以作为方法直接调用。后一种方式在复杂项目中提供了灵活性让你能够精确控制路由配置的时机与方式。在默认应用中显式配置默认的 Bottle 应用模块级bottle.route绑定的就是它同样支持直接调用import bottle def setup_routing(): bottle.route(/, GET, index) bottle.route(/edit, [GET, POST], edit)在自定义 Bottle 实例上显式配置任何Bottle实例都可以用同样的方式配置路由from bottle import Bottle def setup_routing(app): app.route(/new, [GET, POST], form_new) app.route(/edit, [GET, POST], form_edit) app Bottle() setup_routing(app)从Bottle.route的签名bottle.py#L847-L896可以看到它的完整参数为route(path, methodGET, callbackNone, nameNone, applyNone, skipNone, **config)支持path请求路径或路径列表若省略则根据函数签名自动推断见yieldroutesmethodHTTP 方法GET、POST、PUT……或方法列表默认GETcallback用于绕过装饰器语法的快捷参数route(..., callbackfunc)等价于route(...)(func)name路由名用于Router.build()反向生成 URLapply/skip控制插件的应用与跳过**config路由级配置会存入路由专属的配置 overlay。Bottle还提供了get、post、put、delete、patch等便捷方法bottle.py#L898-L916内部都只是对route的封装。此外一条回调可以被绑定到多条路由——docs/tutorial.rst中的route(/)与route(/hello/name)叠用就是典型示例。匹配顺序与优先级理解匹配顺序对设计路由至关重要这些规则可以从Router.matchbottle.py#L430-L464与_compilebottle.py#L405-L415的实现中确认静态路由优先默认情况下strict_orderFalse静态路由在动态路由之前被检查若构造Router(strictTrue)则按注册顺序匹配同一方法内动态路由按注册顺序依次尝试命中即返回因此更早注册的规则拥有更高优先级合并正则的性能优化_compile会将最多_MAX_GROUPS_PER_PATTERN 99条动态路由合并进一个组合正则受 CPython 正则组数上限约束bottle.py#L276-L278每批组合依次尝试HEAD 请求的方法回退匹配HEAD时会依次尝试PROXY、HEAD、GET、ANY其他方法则尝试PROXY、该方法本身、ANYANY方法的优先级test_dynamic_before_static_any与test_any_static_before_dynamic验证了静态ANY路由的优先级低于动态GET路由但高于动态ANY路由这一微妙规则同规则重复注册会覆盖之前的目标DEBUG 模式下会发出警告bottle.py#L393-L401。test_lots_of_routes用超过 99 条动态路由验证了分批编译在大规模路由下的正确性可作为设计大量路由时的参考。反向构建 URL 与调试建议Router.build(name, **kwargs)bottle.py#L417-L428可以根据命名路由反向生成 URL这在需要动态拼接链接如分页、重定向时非常有用# 注册命名路由 app.route(/user/name/age:int, nameprofile) # 反向构建URL 参数会经过 to_url 转换int 会转回字符串 url app.get_url(profile, namealice, age30)构建时缺少必填参数会抛出RouteBuildError额外传入的键会被拼接到查询字符串。test/test_router.py的testBuild、testBuildAnon、testBuildFilter覆盖了命名路由、匿名通配符与带过滤器的路由的构建行为。调试路由时还可以利用以下几点开启 DEBUG 模式DEBUGTrue可以让重复路由的覆盖行为产生警告并在路由注册时立即prepare()bottle.py#L845便于尽早暴露问题用test/test_router.py中的模式自行编写断言向Router添加规则后用{PATH_INFO: ..., REQUEST_METHOD: ...}环境调用match()检查返回的目标与参数字典路由规则语法出错如正则非法时Router.add会抛出RouteSyntaxErrorbottle.py#L362-L366可在开发阶段快速定位规则书写问题。本文核心内容源自仓库文档 docs/routing.rst规则解析与匹配的底层实现细节可在 bottle.py 的Router类中查阅相关行为均有 test/test_router.py 的测试用例佐证动态路由的入门示例可继续阅读 docs/tutorial.rst 中的 Dynamic Routes 一节。赞分享后端Web框架【免费下载链接】bottlebottle.py is a fast and simple micro-framework for python web-applications.项目地址https://gitcode.com/gh_mirrors/bo/bottle点击查看免费下载相关推荐Hugo Glob 模式匹配完全指南路径通配符语法与实战规则详解Hugo Glob 模式匹配完全指南路径通配符语法与实战规则详解 本篇指南围绕 Hugo 官方文档中用于全局路径匹配的 glob 模式glob patter开发工具前端CLIVideoSrt过滤器设置完全指南语气词过滤与自定义规则配置VideoSrt过滤器设置完全指南语气词过滤与自定义规则配置 VideoSrt是一款强大的开源Windows GUI工具能够自动识别视频语音并生成字幕SRT语音音频人工智能java-reader手写框架篇手写Jedis、easy-dubbo与简易MVC彻底内化框架灵魂java reader手写框架篇手写Jedis、easy dubbo与简易MVC彻底内化框架灵魂 java reader 是一位资深Java工程师沉淀了30上一篇TweakPHP性能优化提升大型PHP项目加载速度的方法下一篇终极指南Terraform Provider for VMware vSphere 如何彻底改变你的虚拟化管理流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考