Werkzeug
是一个Python写成的WSGI
工具集。它遵循WSGI
规范,对服务器和Web应用之间的“中间层”进行了开发,衍生出一系列很是有用的Web服务底层模块。正则表达式
Werkzeug库的routing
模块的主要功能在于URL解析。对于WSGI
应用来说,不一样的URL对应不一样的视图函数,routing
模块则会对请求信息的URL进行解析并匹配,触发URL对应的视图函数,以今生成一个响应信息。routing
模块的解析和匹配功能主要体如今三个类上:Rule
、Map
和MapAdapter
。服务器
Rule
类Rule
类继承自RuleFactory
类。一个Rule
的实例表明一个URL模式,一个WSGI
应用能够处理不少不一样的URL模式,这也就是说能够产生不少不一样的Rule
实例。这些Rule
实例最终会做为参数传递给Map
类,造成一个包含全部URL模式的对象,经过这个对象能够解析并匹配请求对应的视图函数。app
关于Rule
类有一些经常使用的方法:函数
empty()
——在实际状况中,Rule
实例会和一个Map
实例进行绑定。经过empty()
方法能够将Rule
实例和Map
实例解除绑定。工具
get_empty_kwargs()
——在empty()
方法中调用,能够得到以前Rule
实例的参数,以便从新构造一个Rule
实例。post
get_rules(map)
——这个方法是对RuleFactory
类中get_rules
方法的重写,返回Rule
实例自己。url
refresh()
——当修改Rule
实例(URL规则)后能够调用该方法,以便更新Rule
实例和Map
实例的绑定关系。spa
bind(map, rebind=False)
——将Rule
实例和一个Map
实例进行绑定,这个方法会调用complie()
方法,会给Rule
实例生成一个正则表达式。设计
complie()
——根据Rule
实例的URL模式,生成一个正则表达式,以便后续对请求的path
进行匹配。code
match(path)
——将Rule
实例和给定的path
进行匹配。在调用complie()
方法生成的正则表达式将会对path
进行匹配。若是匹配,将返回这个path
中的参数,以便后续过程使用。若是不匹配,将会由其余的Rule
实例和这个path
进行匹配。
注意: 在对给定的URL进行匹配的过程当中,会使用一些Converters
。关于Converters
的信息后续加以介绍。
Map
类经过Map
类构造的实例能够存储全部的URL规则,这些规则是Rule
类的实例。Map
实例能够 经过后续的调用和给定的URL进行匹配。
关于Map
类有一些经常使用的方法:
add(rulefactory)
——这个方法在构造Map
实例的时候就会调用,它会将全部传入Map
类中的Rule
实例和该Map
实例创建绑定关系。该方法还会调用Rule
实例的bind
方法。
bind
方法 ——这个方法会生成一个MapAdapter
实例,传入MapAdapter
的包括一些请求信息,这样能够调用MapAdapter
实例的方法匹配给定URL。
bind_to_environ
方法 ——经过解析请求中的environ
信息,而后调用上面的bind
方法,最终会生成一个MapAdapter
实例。
MapAdapter
类MapAdapter
类执行URL匹配的具体工做。关于MapAdapter
类有一些经常使用的方法:
dispatch
方法 ——该方法首先会调用MapAdapter
实例的match()
方法,若是有匹配的Rule
,则会执行该Rule
对应的视图函数。
match
方法 ——该方法将会进行具体的URL匹配工做。它会将请求中的url和MapAdapter
实例中的全部Rule
进行匹配,若是有匹配成功的,则返回该Rule
对应的endpoint
和一些参数rv
。endpoint
通常会对应一个视图函数,返回的rv
能够做为参数传入视图函数中。
为了说明routing
模块的工做原理,这里使用Werkzeug
文档中的一个例子,稍加改动后以下所示:
from werkzeug.routing import Map, Rule, NotFound, RequestRedirect, HTTPException
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 ['Rule points to %r with arguments %r' % (endpoint, args)]
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, application)复制代码
这里咱们使用werkzeug
自带的服务器模块构造了一个Web服务器,而且设计了一个简单的WSGI
应用——application
。这个Web服务器能够根据URL的不一样返回不一样的结果。关于服务器的构造这里再也不赘述,如下部分简单对URL Routing
过程进行分析:
设计URL模式的过程就是构造Rule
实例的过程。上面的例子中咱们构造了8个Rule
实例,分别对应8个不一样的URL模式。每一个Rule
实例还对应一个endpoint
,这个endpoint
能够和视图函数进行对应,以便访问某个URL时,能够触发与之对应的视图函数。下面的例子展现了endpoint
和视图函数的对应关系。
from werkzeug.wrappers import Response
from werkzeug.routing import Map, Rule
def on_index(request):
return Response('Hello from the index')
url_map = Map([Rule('/', endpoint='index')])
views = {'index': on_index}复制代码
构造Map实例时,会调用它的add(rulefactory)
方法。这个方法会在Map实例和各个Rule实例之间创建绑定关系,并经过调用Rule实例的bind()
方法为每一个Rule实例生成一个正则表达式。
例如,对于'/about'
这个URL,它对应的正则表达式为:
'^\\|\\/about$'
对于'/<int:year>/<int:month>/<int:day>/'
这个URL,它对应的正则表达式为:
'^\\|\\/(?P<year>\\d+)\\/(?P<month>\\d+)\\/(?P<day>\\d+)(?<!/)(?P<__suffix__>/?)$'
在设计WSGI
应用时,上述例子经过url_map.bind_to_environ(environ)
构建了一个MapAdapter实例。这个实例将请求的相关信息和已经建立好的Map
实例放在一块儿,以便进行URL匹配。
进行URL匹配的过程是经过调用MapAdapter实例的match()
方法进行的。实质上,这个方法会将请求中的path
传入到全部Rule实例的match(path)
方法中,通过正则表达式的匹配来分析path
是否和某个Rule实例匹配。若是匹配则返回对应的endpoint
和其余的参数,这能够做为参数传入视图函数。
以后,访问URL能够获得相对应的结果。
例如,访问http://localhost:4000/2017/
,能够获得:
Rule points to 'blog/archive' with arguments {'year': 2017}
访问http://localhost:4000/2017/3/20/
,能够获得:
Rule points to 'blog/archive' with arguments {'month': 3, 'day': 20, 'year': 2017}
访问http://localhost:4000/about
,能够获得:
Rule points to 'blog/about_me' with arguments {}
本文章原载于个人技术博客,欢迎你们访问。水平有限,若有不当之处还请指正,谢谢~