前言
Flask 是目前为止我最喜欢的一个 Python web 框架了, 为了更好的掌握其内部实现机制, 这两天准备学习下 Flask 的源码, 将由浅入深跟大家分享下, 其中 Flask 版本为 1.1.1.
Flask 开发初探
正文
本文将结合源码跟踪看下 Flask 是如何启动并运行一个服务的.
首先, 继续贴上最简单的应用:
- from flask import Flask
- App = Flask(__name__)
- @App.route('/')
- def hello_world():
- return 'Hello Flask!'
- if __name__ == '__main__':
- App.run()
我们看到, 这段代码先初始化了 Flask 类并被 App 所指向, 然后执行 run() 来启动程序的.
查看 run 方法:
- 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
首先入参:
参数 | 说明 |
---|---|
host | 服务器地址,不设置的话默认为 127.0.0.1 |
port | 端口,不设置的话默认为 5000 |
debug | 是否为调试模式, 默认为否 |
load_dotenv | 设置环境变量 |
options |
该方法的处理流程是: 对入参进行配置处理之后, 执行 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 服务启动的流程.
来源: https://www.cnblogs.com/ybjourney/p/11717347.html