本篇介绍Flask的启动流程与请求处理流程
Flask流程
先把结果列出来:
1 | 参考简化后的web服务器实现思路,socket建立后,监听recv导的请求信息并解析,然后调用响应的app.route对应的view.func整个流程大致分为两部分(项目启动,处理请求): |
下面是一个很简单的flask例子,通过它我们将理解Flask的处理流程。
Flask启动流程
我们先编写一个简单的Flask项目,右键运行。
点击查看 Flask(__name__)
的源码; 点击查看 app.run()
源码
1 | from flask import Flask,globals |
路由处理:
- 在Map中通过url获取endpoint
- 在self.view_funcs 中使用endpoint为key获取视图函数。
👇在下面这段源码中,
1 | __init__ |
👇在下面这段源码中,通过werkzeug.serving的run_simple函数来进行启动Server ,在这个函数中,将会执行inner函数,接着点击进入inner中的make_server。
1 | # flask/app.py |
👇在下面这段源码中,将创建一个服务器实例。接着点击进入BaseWSGIServer(单进程的server)
1 | # werkzeug/serving.py |
👇在下面这段源码中,封装了处理请求类(WSGIRequestHandler),调用了HTTPServer的初始化。点击进入HTTPServer
1 | class BaseWSGIServer(HTTPServer, object): |
👇在下面这段源码中,将调用TCPServer的初始化方法,点击进入TCPServer
1 | # Lib/http/server.py |
👇在下面这段源码中,将执行BaseServer的初始化,这样一个服务器实例就创建好了
1 | # Lib/socketserver.py |
👇 make_server执行结束后,实现了HTTPServer和BaseServer的初始化,回到run_simple,点击进入 srv.serve_forever()
1 | # werkzeug/serving.py |
👇在下面这段源码中,将建立socket服务开始监听,当 ready 也就是有请求到来的时候使用 _handle_request_noblock
处理请求。这里涉及到了I/O多路复用,简单的提一下,使用它的目的是,我们发现多线程处理消息,CPU在上下文中切换的消耗是非常大的,所以希望用单线程来处理大量用户同时连接。
1 | # Lib/socketserver.py |
小结
以上为Flask的启动流程,提炼一下内容:
1 | flask.Flask.run -> werkzeug.serving.run_simple -> |
我们接着继续!
Flask请求处理流程
接上面结尾处,点击进入 _handle_request_noblock
,👇在下面这段源码中,get_request 是socket对象的accept方法用来与用户建立连接。然后开始校验请求、处理请求。点击进入process_request
1 | # Lib/socketserver.py |
👇在下面这段源码中,在ForkingMixIn/ThreadingMixIn中进行重写,点击进入finish_request。
1 | class BaseServer: |
👇在下面这段源码中,实际中是调用 WSGIRequestHandler 来处理请求(见前面初始化BaseServer),对于WSGIRequestHandler 它是一个werkzeug中对WSGI请求的处理类。初始化这个类将执行 handle
方法 。在这个方法中执行 try: self.handle()
1 | class BaseServer: |
在前面都还没有涉及到app,都是werkzeug(http -> socket)相关的。
重新寻找:
在 run_simple -> make_server -> BaseWSGIServer的 __init__
方法内 handler = WSGIRequestHandler
点击进入 WSGIRequestHandler
👇在下面这段源码中,werkzeug.serving.WSGIRequestHandler.handle_one_request
调用werkzeug.serving.WSGIRequestHandler.run_wsgi
开始处理请求。其中 self.server.app
保存的是我们的 Flask对象,然后对对象加括号,执行执行Flask的 __call__
方法
1 | class WSGIRequestHandler(BaseHTTPRequestHandler, object): |
重新寻找:
从 app = Flask(__name__)
点击进入,寻找 __call__
方法。
👇在下面这段源码中,wsgi_app在请求上下文中执行我们编写的预处理方法(before request),视图方法,后响应方法等(after request)。点击进入wsgi_app
1 | # flask/app.py |
👇在下面这段源码中,首先创建请求上下文对象,然后执行视图函数,返回response响应,最终删掉请求上下文,应用上下文。点击进入 ctx.push()
; 点击进入 self.full_dispatch_request()
1 | # flask/app.py |
👇在下面这段源码中,将应用上下文对象放入LocalStack、将请求上下文对象放入LocalStack。
1 | # flask/ctx.py |
👇在下面这段源码中,将执行请求的预处理、视图、后处理以及异常捕获和错误处理。点击进入 self.dispatch_request()
1 | # flask/app.py |
👇在下面这段源码中,将执行视图。
1 | # /flask/ctx.py |
小结
首尾:werkzeug相关
1 | curl发出请求->socket接受到请求 -> |
中间:app相关
1 | 当用户请求到来之后,flask内部会创建两个对象: |
参考文章 [flask源码走读]