1,本文主要梳理了flask源码中route路由的设计思路。
首先,从WSGI协议的角度介绍flask route的作用;
其次,详细讲解如何借助werkzeug库的Map、Rule实现route;
最后,梳理了一次完整的http请求中route的完整流程。
2,源码版本说明
本文参考的是flask 0.5版本的代码。
flask 0.1版本的代码非常短,只有600多行,但是这个版本缺少blueprint机制。
3,flask route示例
直接使用flask官方文档中的例子
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
此例中,使用app.route装饰器,完成了以下两个url与处理函数的route:
- 1
- 2
- 3
- 4
这样做的效果为:
当http请求的url为’/’时,flask会调用hello_world函数;
当http请求的url为’/post/<某整数值>’(例如/post/32)时,flask会调用show_post函数;
4,flask route的作用
从上面的示例中其实可以明白:flask route的作用就是建立url与处理函数的映射。
WSGI协议将处理请求的组件按照功能及调用关系分成了三种:server, middleware, application。
其中,server可以调用middleware和application,middleware可以调用application。
符合WSGI的框架对于一次http请求的完整处理过程为:
1,server读取解析请求,生成environ和start_response;
2,然后调用middleware,middleware完成自己的处理部分后,可以继续调用下一个middleware或application,形成一个完整的请求链;
3,application位于请求链的最后一级,其作用就是生成最终的响应。
- 1
- 2
特别重要的:
在上节的示例中app = Flask(_name_)创建了一个middleware,
而这个middleware的核心作用是进行请求转发(request dispatch)。
进行请求转发的前提就是能够建立url与处理函数之间的映射关系,即route功能。
因此,在flask中,route是Flask类的一个装饰器。
5,flask route的实现思路
通过上一小节,我们知道以下两点:
- 1
- 2
那么,如果是我们自己来实现route,思路也很简单:
- 1
- 2
- 3
- 4
flask的实现思路也是这样的。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
至此, 一个简单的Flaskmiddleware的骨架就完成了。
上面的Flask类主要功能包括:
- 1
- 2
- 3
当然,在实际中,不可能这么简单,但是基本思路是一致的。
6,werkzeug库中的Map与Rule在Flask中的应用
需要指出,上面实现的最简单的Flask类还是有很多问题的。
比如,HTTP请求中相同的url,不同的请求方法,比如GET,POST如果对应不同的处理函数,该如何处理?
flask使用了werkzeug库中的Map和Rule来管理url与处理函数映射关系。
Rule的主要作用是保存了一组url,endpoint,methods关系
每个(url, endpoint, methods)都有一个对应的Rule对象:
其实现如下:
- 1
- 2
- 3
- 4
- 5
这里需要解释一下endpoint:
前面说过:url与其处理函数可以使用一个字典来实现:{url: function}
flask在实现的时候,在中间加了一个中介endpoint,于是,url与处理函数的映射变成了这样:
- 1
- 2
- 3
- 4
- 5
于是,刚才我们实现的简单的flask骨架中{url: function}的字典,就变成了{endpoint: function},
而{url: endpoint}这个映射关系就需要借助Map和Rule这两个类来完成。
可以发现:endpoint就是url和处理函数映射关系中的一个中介,所以,它可以是任何可以用作字典键的值,比如字符串。
但是在实际使用中endpoint,一般endpoint均为字符串,并且默认情况下:
- 1
- 2
因为,每建立一个url–>endpoint–>function关系就会创建一个Rule对象,所以,会有很多Rule对象存在。
Map的作用则是保存所有Rule对象
所以,一般情况下Map的用法如下:
- 1
- 2
- 3
- 4
- 5
在flask的源码中
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
7,route的完整流程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
这样,就完成了对url和响应函数的映射关系。
下一步,调用WSGI server响应http请求,在文章开始的示例中使用:
- 1
调用python标准库提供的WSGI server,在实际使用时,可能是gunicorn或uwsgi。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
至此,就完成了完整的route。
8,总结
1,flask的Flask类是WSGI的dispatch middleware;
2,Flask的url_map保存所有的(url, endpoint, method)映射关系;
3,Flask的view_functions保存所有的{endpoint: function}映射关系;
4,dispath request就是根据url找到endpoint,再根据endpoint找到function,最后调用function的过程
9,参考资料链接如下:
- 1
- 2