一、WSGI程序
在分析flask的启动流程之前,我们有必要了解一些web程序的基础——WSGI。flask的核心Werkzeug是一个WSGI工具库,WSIGI(Python Web Server Gateway Interface)是为了让web服务器与python程序能够进行数据交流而定义的一套接口标准。
根据WSGI标准的规定,web程序必须是一个可调用对象,该对象接收两个参数:
- environ: 包含请求的所有信息,是一个字典对象
- start_response: 需在可调用对象中调用的函数,用来发起响应,参数是状态码,响应头等
WSGI服务器会在调用这个可调用对象时传入这两个参数。另外,该可调用对象还需要返回一个可迭代的对象。
一个简单的WSGI程序如下:
1 | from wsgiref.simple_server import make_server |
hello()函数就是一个可调用对象,也就是web程序,返回含有一个字节串的列表,这是因为WSGI规定了请求和响应主体应该为字节串。
python提供了wsgiref库,可作为一个简易的WSGI服务器在开发时使用。make_server()方法创建了一个本地服务器,分别传入主机地址、端口和可调用对象。最后通过server_forver()启动。
WSGI服务器启动后会监听传入主机对应的端口,当收到请求时,会把请求报文解析成一个environ字典,然后调用可调用对象,将environ、start_response作为参数传入。
运行该程序,在浏览器输入localhost:5000后便能看见一行’hello world’。
Gunicorn、uWSGI等都是实现了WSGI规范的服务器,正是因为遵循了统一的规范,所以这些服务器都可以运行flask程序。
二、flask的工作流程
1.程序启动
flask提供了两种启动服务器的方式:
- 命令行中输入flask run(实际调用flask.cli.run_command())
- 调用flask.Flask.run()方法
无论哪种方法,最后都是调用了werkzeug.serving模块中的run_simple()函数
函数如下:
1 | def run_simple(hostname, port, application, use_reloader=False, |
此方法最后会调用inner()函数,它使用make_server()创建服务器,之后调用server_forever()方法运行服务器。当收到请求时,WSGI服务器会调用web程序中提供的可调用对象,该对象就是实例app。
2.请求和响应
Flask类实现了__call__
方法,当实例被调用时会执行该方法,这个方法内部调用了wsgi_app()方法:
1 | def wsgi_app(self, environ, start_response): |
通过wsgi_app方法的参数就能看出,wsgi_app()方法就是隐藏在Flask中的WSGI程序。
该方法包括了上下文的生成,请求的分发,返回请求的响应。
其中,比较重要的一个就是请求上下文的生成,也就是 request_context() 以及 push() 到栈中,其中的 class RequestContext 就是保持一个请求的上下文的变量,在请求到来之前 _request_ctx_stack 一直是空的,当请求到来的时候会调用 ctx.push() 向栈中添加上下文信息。
在每次请求调用结束后,也就是在 wsgi_app() 中的 finally 中会调用 ctx.auto_pop(error),该函数中会根据情况判断是否清除放在 _request_ctx_stack 中的 ctx 。
关于上下文的详细内容可以参考 这篇文章 。
接下来是处理请求的分发。
1 | def full_dispatch_request(self): |
在 dispatch_request() 函数中就会匹配并调用对应的视图函数,获取其返回值,将返回值赋值给rv。最后,接收视图函数返回值的finalize_request会用这个值来生成响应