flask源码走读
Flask-Origin
源码版本
一直想好好理一下flask的实现,这个项目有Flask 0.1版本源码并加了注解,挺清晰明了的,我在其基础上完成了对Werkzeug的理解部分,大家如果想深入学习的话,可以参考werkzeug_flow.md.
阅读前
为了更容易理解Flask的实现原理,你需要对WSGI协议以及HTTP协议有一些了解,建议先简单浏览下面的基本知识:
Flask内部实现大量依赖于Werkzeug,包括请求和响应对象,路由匹配,URL生成等等,你可以阅读Werkzeug的文档来深入了解这些内容的具体实现。另外,如果你对模板渲染部分的内容感兴趣,也可以考虑阅读Jinja2文档:
werkzeug源码阅读,可以参考下面的函数打断点,再测试一个请求,理清过程。
其实可以参考简化后web服务实现思路,socket建立后,监听recv到的请求信息(no_wsgi_dome.no_wsgi.Socket._handle)并解析,然后调用相应的app.route对应的view_func.整个过程可以大致分为两部分:
1. app-> werkzeug-> http-> socket 启动端口监听,注册各种方法.
2. socket recv到请求-> 初始化RequestHandlerClass-> 调用Flask.__call__, wsgi_app在请求上下文中执行预处理方法,视图方法,后响应方法等.
flask启动流程,只追溯了app到http再到socket的启动,主流程就是BaseWSGIServer初始化调用了HTTPServer的初始化,进而初始化了BaseServer,在socketserver上启动了服务开始监听端口:
flask.Flask.run -> werkzeug.serving.run_simple ->
werkzeug.serving.run_simple.inner ->werkzeug.serving.make_server ->
BaseWSGIServer->HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler) ->
BaseServer.__init__(self, server_address, RequestHandlerClass) ->
werkzeug.serving.run_simple.inner.srv.serve_forever() ->
socketserver.BaseServer.serve_forever 建立socket服务开始监听,当ready也就是有recv到请求时开始 _handle_request_noblock
flask处理请求流程,追溯了socket接受到请求后触发app处理请求的主流程:
curl发出请求->socket接受到请求 ->
SocketServer.BaseServer.serve_forever._handle_request_noblock ->
SocketServer.BaseServer.process_request ->
SocketServer.BaseServer.finish_request ->
socketserver.BaseServer.__init__:self.RequestHandlerClass(request, client_address, self) ->
这里要找出RequestHandlerClass是如何初始化的,它的真身是什么 ->
socketserver.TCPServer.__init__:BaseServer.__init__(self, server_address, RequestHandlerClass) ->
http.server.HTTPServer(未重写__init__) ->
werkzeug.serving.BaseWSGIServer:HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler) (此处handler就是WSGIRequestHandler) ->
RequestHandlerClass的真身已经找到,就是WSGIRequestHandler 也就是说每次请求来了都初始化一个WSGIRequestHandler去处理 ->
处理的入口应该是werkzeug.serving.WSGIRequestHandler.handle可是简单一看并没找到是如何开始处理请求的->
往它的父类BaseHTTPRequestHandler中找也没有 ->
再往上socketserver.StreamRequestHandler ->
找到了SocketServer.BaseRequestHandler.__init__:try:self.handle() 关键点 ->
开始调用子类WSGIRequestHandler中的handle方法 ->
werkzeug.serving.WSGIRequestHandler (注意handler和handle_one_request,WSGIRequestHandler重载了BaseHTTPServer.BaseHTTPRequestHandler中的方法,BaseHTTPRequestHandler由重载了 SocketServer.BaseRequestHandler )->
werkzeug.serving.WSGIRequestHandler.handle_one_request调用werkzeug.serving.WSGIRequestHandler.run_wsgi 开始处理请求 ->
run_wsgi.execute(self.server.app)将请求交予app来处理 ->
flask.Flask.__call__ ->
flask.Flask.wsgi_app 开始app内的流程,交由wsgi_app在请求上下文中执行预处理方法,视图方法,后响应方法等。
可以看到实现过程中Server,Handler用到了继承并重载,层层包装了web服务
BaseWSGIServer继承了HTTPServer重写了BaseServer.serve_forever(包了一层),
HTTPServer继承了TCPServer重写了server_bind,
TCPServer继承了BaseServer重写了server_bind,
主要思路要理清socket接受接请求后如何用请求触发调用app,这里主要是SocketServer.BaseRequestHandler.__init__:try:self.handle() 这个__init__才是处理请求真正开始的地方.
进一步
- web的最原始的实现见 no_wsgi_dome ,不使用werkzeug,不使用wsgi约束,只是用socket如何实现http服务.这个对理解wsgi对http以及socket的封装有很好的借鉴意义.
- 补充了本地上下文相关的本地线程、本地堆栈、本地代理,并写了个LocalProxy_dome.py 辅助理解flask中是如何使用LocalProxy的。
- 我通过打断点,理通了app的启动和接受请求到处理请求的过程,可以参考werkzeug_flow.md配合flask_dome.py并手动打断点尝试一下.
- 根据下面的提示,自己理一下吧.
- Flask中的请求响应循环
- 路由系统
- 本地上下文
- 请求与响应对象
- session
- 蓝本
- 模板渲染
最后,要是觉得不错的话,点个赞支持一下吧,相关源码都放到了 我的github.
flask源码走读的更多相关文章
- Python Web Flask源码解读(三)——模板渲染过程
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- flask源码分析
本flask源码分析不间断更新 而且我分析的源码全是我个人觉得是很beautiful的 1 flask-login 1.1 flask.ext.login.login_required(func),下 ...
- Flask源码学习—config配置管理
自己用Flask做了一个博客(www.hbnnlove.sinaapp.com),之前苦于没有对源码解析的文档,只能自己硬着头皮看.现在我把我自己学习Flask源码的收获写出来,也希望能给后续要学习F ...
- Apache Spark源码走读之23 -- Spark MLLib中拟牛顿法L-BFGS的源码实现
欢迎转载,转载请注明出处,徽沪一郎. 概要 本文就拟牛顿法L-BFGS的由来做一个简要的回顾,然后就其在spark mllib中的实现进行源码走读. 拟牛顿法 数学原理 代码实现 L-BFGS算法中使 ...
- Apache Spark源码走读之16 -- spark repl实现详解
欢迎转载,转载请注明出处,徽沪一郎. 概要 之所以对spark shell的内部实现产生兴趣全部缘于好奇代码的编译加载过程,scala是需要编译才能执行的语言,但提供的scala repl可以实现代码 ...
- Apache Spark源码走读之13 -- hiveql on spark实现详解
欢迎转载,转载请注明出处,徽沪一郎 概要 在新近发布的spark 1.0中新加了sql的模块,更为引人注意的是对hive中的hiveql也提供了良好的支持,作为一个源码分析控,了解一下spark是如何 ...
- Apache Spark源码走读之7 -- Standalone部署方式分析
欢迎转载,转载请注明出处,徽沪一郎. 楔子 在Spark源码走读系列之2中曾经提到Spark能以Standalone的方式来运行cluster,但没有对Application的提交与具体运行流程做详细 ...
- twitter storm 源码走读之5 -- worker进程内部消息传递处理和数据结构分析
欢迎转载,转载请注明出处,徽沪一郎. 本文从外部消息在worker进程内部的转化,传递及处理过程入手,一步步分析在worker-data中的数据项存在的原因和意义.试图从代码实现的角度来回答,如果是从 ...
- 用尽洪荒之力学习Flask源码
WSGIapp.run()werkzeug@app.route('/')ContextLocalLocalStackLocalProxyContext CreateStack pushStack po ...
随机推荐
- web项目继承ServletContainerInitializer进行访问HttpServlet(WebServlet)
java使用web项目不需要加web.xml 配置javax.servlet.ServletContainerInitializer 1.在src目录创建META-INF,META-INF目录下创建s ...
- NSString,NSData,NSFileManager常用方法
一.利用NSString类进行文件路径的处理 文件路径格式: NSString *path=@"/Uesrs/apple/testfile.txt" 常用方法汇总: 1.获得组成此 ...
- 再看redux
redux提供了一个全局的唯一状态树,不代表就不需要组建本身的state. 何时用react组件的state.props?? state只表示一些‘临时的’‘内部的’状态数据.临时的:代表你可以临时改 ...
- PHP变量定义及工作原理
1.变量定义: 通常学到的是,变量代表存储空间以及其中数据的一个“标识符”. 变量名 指向 变量值 更深入的说是 变量指向内存的一块区域 2.变量工作原理,通过画图分析法——内存空间 <?php ...
- 基于原生JS封装数组原型上的sort方法
基于原生JS封装数组原型上的sort方法 最近学习了数组的原型上内置方法的封装,加强了用原生JS封装方法的能力,也进一步理解数组方法封装的过程,实现的功能.虽然没有深入底层,了解源码.以下解法都是基于 ...
- %.*lf控制输出长度
#include<stdio.h> int main(){ int a,b,c; while(scanf("%d%d%d",&a,&b,&a ...
- P2257 YY的GCD
P2257 YY的GCD 题目描述 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对 k ...
- title中添加小图标
<title>标签中不能添加图片,但是可以添加小图标. 步骤: 1.做一个16 X 16像素的ico格式的图标.具体操作方法是,先在Photoshop中做一个透明背景的16 X 16像素P ...
- Docker入门系列02
上篇用一个简单的示例,简单的介绍了 Dockerfile 的配置及其相关的命令.这一篇会在上篇的示例程序里,继续添加新代码及如何将单元测试也放入 Image 建立过程内. 首先,我们需要建一个新的类库 ...
- 使用GeoServer发布shp数据为WMS服务和WFS服务
使用GeoServer发布shp数据为WMS服务和WFS服务 1安装GeoServer 2使用GeoServer上传数据 3使用GeoServer发布数据为WMS和WFS 看完本教程,你将学会安装Ge ...