flask源码走读

智数映雪鹤
• 阅读 1779

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__才是处理请求真正开始的地方.

进一步

  1. web的最原始的实现见 no_wsgi_dome ,不使用werkzeug,不使用wsgi约束,只是用socket如何实现http服务.这个对理解wsgi对http以及socket的封装有很好的借鉴意义.
  2. 补充了本地上下文相关的本地线程、本地堆栈、本地代理,并写了个LocalProxy_dome.py 辅助理解flask中是如何使用LocalProxy的。
  3. 我通过打断点,理通了app的启动和接受请求到处理请求的过程,可以参考werkzeug_flow.md配合flask_dome.py并手动打断点尝试一下.
  4. 根据下面的提示,自己理一下吧.

    • Flask中的请求响应循环
    • 路由系统
    • 本地上下文
    • 请求与响应对象
    • session
    • 蓝本
    • 模板渲染

最后,要是觉得不错的话,点个赞支持一下吧,相关源码都放到了 我的github.

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Irene181 Irene181
4年前
小伙Python爬虫并自制新闻网站,太好玩了
大家好,我又来了,我是银牌厨师豆腐!我们总是在爬啊爬,爬到了数据难道只是为了做一个词云吗?当然不!这次我就利用flask为大家呈现一道小菜。Flask是python中一个轻量级web框架,相对于其他web框架来说简单,适合小白练手。使用Flask爬虫,教大家如何实时展示自己爬下来的数据到网页上。先给大家展示一下这个丑丑的网页↓(给个面子,别笑)演示三
浅梦一笑 浅梦一笑
4年前
Flask--如何在pycharm中导入并运行flask项目
一.导入flask项目FileOpen选择需要导入flask项目(如项目名为flasky)。二.设置解释器FileSettingsProjectInterpreter,如下图所示三.添加Flaskserver1.点击pycharm右上角的AddConfiguration2.点击号,选择FlaskServer3.填写参数4.运行项目点击pychar
Karen110 Karen110
3年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Stella981 Stella981
3年前
Flask, Django
1\.目录结构一般情况下,Django很系统、统一。Flask项目目录风格不同一,即使用上了蓝图。2\.数据库迁移Flask要用第三方extensions,而Django自带,这个很方便。3\.模块化Flask是用蓝图。Django可以自动生成pythonmanage.pystartapp<app_n
Stella981 Stella981
3年前
Flask框架
FLask框架的简单介绍Flask是一个基于Python开发并且依赖jinja2模板和WerkzeugWSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用
Wesley13 Wesley13
3年前
#Python 3 转义#
!Guu(https://static.oschina.net/uploads/img/201708/28195412_W7LR.jpg)问题最近一直在忙SWT项目的前端和后端整合的工作,目前已经基本把前端和后台的flask搞定,剩下是要与数据库,分析服务器对接了。今天解决了个python的转义的问题,本来我是想通过flask返回列表数据
Stella981 Stella981
3年前
Flask源码阅读
源码coding:utf8"""flask._compat~~~~~~~~~~~~~Somepy2/py3compatibilitysupportbasedonastrippeddownversionofsixsowedon'thavetodependona
Wesley13 Wesley13
3年前
Android系统篇之
一、前言今天我们开启Android系统篇的文章了,其实一直想弄,只是之前一直没有太多深入的了解,最近又把这块拿出来好好看了一下,所以想从新梳理一下,来看看Android中的这块知识,首先我们今天来看一下:Android中的智能指针的概念,为什么说先看一下智能指针这个知识呢?因为我们在看Android源码的时候,会发现几乎好多地方都用到了这个东东
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这