Flask原始碼分析一:服務啟動
阿新 • • 發佈:2019-10-22
前言
Flask是目前為止我最喜歡的一個Python Web框架了,為了更好的掌握其內部實現機制,這兩天準備學習下Flask的原始碼,將由淺入深跟大家分享下,其中Flask版本為1.1.1。
Flask系列文章:
- 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服務啟動的流程