WSGI:全稱是Web Server Gateway Interface,WSGI不是服務器,python模塊,框架,API或者任何軟件,只是一種規範,描述服務器端如何與web應用程序通訊的規範。python
Web應用程序的本質就是:web
在客戶端和服務器端WSGI負責協議的轉化,WSGI將web組件分爲三部分:Web服務器、Web中間件、Web應用程序,當服務器接受到HTTP請求時,會按照WSGI協議解析成Request對象並調用WSGI Application,最後將響應返回給瀏覽器。flask
Werkzeug是Python的WSGI規範的實用函數庫。Flask使用的底層WSGI庫就是Werkzeug。瀏覽器
WSGI 中有一個很是重要的概念:每一個 Python web 應用都是一個可調用(callable)的對象。在 Flask 中,這個對象就是 app = Flask(__name__)
建立出來的 app,就是圖中綠色部分。
服務器
要運行Web應用,必須依賴於Web Server,好比咱們常見的Apache、Nginx、Lighttpd以及咱們Flask使用的Werkzug位於黃色部分。app
WSGI規定了server和app之間如何進行通訊,它規定了app(environ, start_response)接口,environ是環境設置的字典,包含了請求的全部信息,start_response是WSGI處理完畢後調用的函數。框架
源碼位置:werkzeug.serving:WSGIRequestHandler中execute()。ide
from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "Hello World" if __name__ == "__main__": app.run()
應用啓動的代碼: app.run()函數
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options): """ ... 部分代碼省略 """ _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 port = int(port or sn_port or _port) from werkzeug.serving import run_simple try: # 導入werkzeug.serving的run_simple(),傳入接受到的參數 # 注意:第三個參數是self: 就是咱們建立的Flask app run_simple(host, port, self, **options) finally: self._got_first_request = False
run_simple(host, port, self, **options)
監聽指定的IP和端口,當接受到請求時,WSGI會解析,而後調用app去執行請求處理的邏輯。對應的邏輯在werkzeug.serving:WSGIRequestHandler的execute()中:
def execute(app): # 調用代碼獲取結果 application_iter = app(environ, start_response) try: for data in application_iter: write(data) if not headers_sent: write(b'') finally: if hasattr(application_iter, 'close'): application_iter.close() application_iter = None
能夠看到application_iter = app(environ, start_response),調用app執行獲取響應結果。url
要調用app實例,那麼會調用其__call__()方法。flask.app:Flask:
def __call__(self, environ, start_response): """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response) def wsgi_app(self, environ, start_response): # 下篇博客講 Flask上下文會解釋,先忽略 ctx = self.request_context(environ) error = None try: try: ctx.push() # 正確的請求路徑,會經過路由分發到響應的視圖處理函數 response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None # 無論處理是否發生異常,都須要把棧中的請求 pop 出來 ctx.auto_pop(error)
上面代碼業務邏輯就是經過路由配置,找到具體處理業務的視圖函數。full_dispatch_request()相關代碼:
def full_dispatch_request(self): """ 分派請求並在此之上執行請求處理 """ self.try_trigger_before_first_request_functions() try: request_started.send(self) rv = self.preprocess_request() if rv is None: rv = self.dispatch_request() except Exception as e: rv = self.handle_user_exception(e) return self.finalize_request(rv)
在這段中核心就是 self.dispatch_request() :
def dispatch_request(self): req = _request_ctx_stack.top.request if req.routing_exception is not None: self.raise_routing_exception(req) rule = req.url_rule if getattr(rule, 'provide_automatic_options', False) \ and req.method == 'OPTIONS': return self.make_default_options_response() # otherwise dispatch to the handler for that endpoint return self.view_functions[rule.endpoint](**req.view_args)
self.dispatch_request()
返回的是處理函數的返回結果(好比Hello World 例子中返回的字符串),finalize_request
會把它轉換成 Response
對象。
在 dispatch_request
以前咱們看到 preprocess_request
,以後看到 finalize_request
,它們裏面包括了請求處理以前和處理以後的不少 hooks:
before_first_request
、before_request、
after_request 、
teardown_request