Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟你们分享下,其中Flask版本为1.1.1。html
Flask系列文章:python
本文将结合源码跟踪看下Flask是如何启动并运行一个服务的。在0.11版本之后,支持命令行启动flask。shell
目前共有两种方式能够载入应用:flask
首先,继续贴上最简单的应用app.py:服务器
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello Flask!' if __name__ == '__main__': app.run()
执行python app.py便可启动。app
咱们看到,这段代码先初始化了Flask类并被app所指向,而后执行run()来启动程序的。框架
查看run方法:socket
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options): if os.environ.get("FLASK_RUN_FROM_CLI") == "true": from .debughelpers import explain_ignored_app_run explain_ignored_app_run() return if get_load_dotenv(load_dotenv): cli.load_dotenv() # if set, let env vars override previous values if "FLASK_ENV" in os.environ: self.env = get_env() self.debug = get_debug_flag() elif "FLASK_DEBUG" in os.environ: self.debug = get_debug_flag() # debug passed to method overrides all other sources if debug is not None: self.debug = bool(debug) _host = "127.0.0.1" _port = 5000 server_name = self.config.get("SERVER_NAME") sn_host, sn_port = None, None if server_name: sn_host, _, sn_port = server_name.partition(":") host = host or sn_host or _host # pick the first value that's not None (0 is allowed) port = int(next((p for p in (port, sn_port) if p is not None), _port)) options.setdefault("use_reloader", self.debug) options.setdefault("use_debugger", self.debug) options.setdefault("threaded", True) cli.show_server_banner(self.env, self.debug, self.name, False) from werkzeug.serving import run_simple try: run_simple(host, port, self, **options) finally: # reset the first request information if the development server # reset normally. This makes it possible to restart the server # without reloader and that stuff from an interactive shell. self._got_first_request = False
首先入参:ide
参数 | 说明 |
---|---|
host | 服务器地址,不设置的话默认为127.0.0.1 |
port | 端口,不设置的话默认为5000 |
debug | 是否为调试模式, 默认为否 |
load_dotenv | 从项目根目录下的.flaskenv 或.env 文件中导入环境变量 |
该方法的处理流程是:对入参进行配置处理以后,执行werkzeug的run_simple()方法,学习
run_simple将启动一个WSGI服务。
关于WSGI协议:
- 它是关于HTTP服务器和Web应用的桥梁,定义了标准接口以提高Web应用之间的可移植性,是一套接口交互规范。
- 它的功能是监听指定端口服务,未来自HTTP服务器的请求解析为WSGI格式,调用Flask app处理请求。
run_simple中的inner方法是核心,inner调用make_server().serve_forever()启动服务。关于make_server:
def make_server(host=None, port=None, app=None, threaded=False, processes=1, request_handler=None, passthrough_errors=False, ssl_context=None, fd=None): if threaded and processes > 1: raise ValueError("cannot have a multithreaded and " "multi process server.") elif threaded: return ThreadedWSGIServer(host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd) elif processes > 1: return ForkingWSGIServer(host, port, app, processes, request_handler, passthrough_errors, ssl_context, fd=fd) else: return BaseWSGIServer(host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd)
make_server会根据线程或者进程数返回相应的WSGI服务器,默认状况下返回BaseWSGIServer,ThreadedWSGIServer和ForkingWSGIServer均集成了BaserWSGIServer,接下来咱们看下serve_forever()方法:
def serve_forever(self): self.shutdown_signal = False try: HTTPServer.serve_forever(self) except KeyboardInterrupt: pass finally: self.server_close()
最终调用了Python标准类库接口HTTPServer的serve_forever()方法,而HTTPServer又是socketserver.TCPServer的子类,经过server_bind来监听服务:
class HTTPServer(socketserver.TCPServer): allow_reuse_address = 1 # Seems to make sense in testing environment def server_bind(self): """Override server_bind to store the server name.""" socketserver.TCPServer.server_bind(self) host, port = self.server_address[:2] self.server_name = socket.getfqdn(host) self.server_port = port
接下来咱们经过flask命令来启动一个应用,hello.py:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello Flask!'
Unix Bash ( Linux 、Mac 及其余):
$ export FLASK_APP=hello $ flask run
这样便启动了该 应用,那么内部的实现机理是怎样的呢?
以上,就是Flask服务启动的流程。