前言:

Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1。

Flask系列文章:

  1. Flask开发初探

正文

本文将结合源码跟踪看下Flask是如何启动并运行一个服务的。

首先,继续贴上最简单的应用:

  1. from flask import Flask
  2. app = Flask(__name__)
  3. @app.route('/')
  4. def hello_world():
  5. return 'Hello Flask!'
  6. if __name__ == '__main__':
  7. app.run()

我们看到,这段代码先初始化了Flask类并被app所指向,然后执行run()来启动程序的。

查看run方法:

  1. def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
  2. if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
  3. from .debughelpers import explain_ignored_app_run
  4. explain_ignored_app_run()
  5. return
  6. if get_load_dotenv(load_dotenv):
  7. cli.load_dotenv()
  8. # if set, let env vars override previous values
  9. if "FLASK_ENV" in os.environ:
  10. self.env = get_env()
  11. self.debug = get_debug_flag()
  12. elif "FLASK_DEBUG" in os.environ:
  13. self.debug = get_debug_flag()
  14. # debug passed to method overrides all other sources
  15. if debug is not None:
  16. self.debug = bool(debug)
  17. _host = "127.0.0.1"
  18. _port = 5000
  19. server_name = self.config.get("SERVER_NAME")
  20. sn_host, sn_port = None, None
  21. if server_name:
  22. sn_host, _, sn_port = server_name.partition(":")
  23. host = host or sn_host or _host
  24. # pick the first value that's not None (0 is allowed)
  25. port = int(next((p for p in (port, sn_port) if p is not None), _port))
  26. options.setdefault("use_reloader", self.debug)
  27. options.setdefault("use_debugger", self.debug)
  28. options.setdefault("threaded", True)
  29. cli.show_server_banner(self.env, self.debug, self.name, False)
  30. from werkzeug.serving import run_simple
  31. try:
  32. run_simple(host, port, self, **options)
  33. finally:
  34. # reset the first request information if the development server
  35. # reset normally. This makes it possible to restart the server
  36. # without reloader and that stuff from an interactive shell.
  37. self._got_first_request = False

首先入参:

参数 说明
host 服务器地址,不设置的话默认为127.0.0.1
port 端口,不设置的话默认为5000
debug 是否为调试模式, 默认为否
load_dotenv 设置环境变量
options

该方法的处理流程是:对入参进行配置处理之后,执行werkzeug的run_simple()方法,

run_simple将启动一个WSGI服务。

关于WSGI协议:

  1. 它是关于HTTP服务器和Web应用的桥梁,定义了标准接口以提升Web应用之间的可移植性,是一套接口交互规范。
  2. 它的功能是监听指定端口服务,将来自HTTP服务器的请求解析为WSGI格式,调用Flask app处理请求。

run_simple中的inner方法是核心,inner调用make_server().serve_forever()启动服务。关于make_server:

  1. def make_server(host=None, port=None, app=None, threaded=False, processes=1,
  2. request_handler=None, passthrough_errors=False,
  3. ssl_context=None, fd=None):
  4. if threaded and processes > 1:
  5. raise ValueError("cannot have a multithreaded and "
  6. "multi process server.")
  7. elif threaded:
  8. return ThreadedWSGIServer(host, port, app, request_handler,
  9. passthrough_errors, ssl_context, fd=fd)
  10. elif processes > 1:
  11. return ForkingWSGIServer(host, port, app, processes, request_handler,
  12. passthrough_errors, ssl_context, fd=fd)
  13. else:
  14. return BaseWSGIServer(host, port, app, request_handler,
  15. passthrough_errors, ssl_context, fd=fd)

make_server会根据线程或者进程数返回相应的WSGI服务器,默认情况下返回BaseWSGIServer,ThreadedWSGIServer和ForkingWSGIServer均集成了BaserWSGIServer,接下来我们看下serve_forever()方法:

  1. def serve_forever(self):
  2. self.shutdown_signal = False
  3. try:
  4. HTTPServer.serve_forever(self)
  5. except KeyboardInterrupt:
  6. pass
  7. finally:
  8. self.server_close()

最终调用了Python标准类库接口HTTPServer的serve_forever()方法,而HTTPServer又是socketserver.TCPServer的子类,通过server_bind来监听服务:

  1. class HTTPServer(socketserver.TCPServer):
  2. allow_reuse_address = 1 # Seems to make sense in testing environment
  3. def server_bind(self):
  4. """Override server_bind to store the server name."""
  5. socketserver.TCPServer.server_bind(self)
  6. host, port = self.server_address[:2]
  7. self.server_name = socket.getfqdn(host)
  8. self.server_port = port

以上,就是Flask服务启动的流程。

版权声明:本文为ybjourney原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ybjourney/p/11717347.html