Flask源碼分析

首先,推薦一個便宜的雲主機,感覺比阿里便宜,新用戶一年68元,滴滴雲
附上活動鏈接:https://i.didiyun.com/2d7Jy4Nzle8

Flask的最小應用程序如下:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World'
    
if __name__ == '__main__':
    app.run()

app.run()

Flask的類從flask包中引入後,直接製造app實例,使用app實例執行run方法。
所以先來看看Flask類中的_init__()和run()方法

def __init__( 
# 這裏用的比較多的是,static_folder,static_url_path靜態目錄的指定,實例中都是默認參數
    self,
    import_name,
    static_url_path=None,
    static_folder="static",
    static_host=None,
    host_matching=False,
    subdomain_matching=False,   
    template_folder="templates",    
    instance_path=None,    
    instance_relative_config=False,    
    root_path=None,
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
    try:
        run_simple(host, port, self, **options)
    finally:
        self._got_first_request = False

run方法中省略調試相關的代碼,關鍵執行代碼是run_simple方法,帶入默認的host和port以及對象,host爲127.0.0.1,port爲5000。那麼就來分析run_simple()

run_simple()

run_simple方法來自werkzeug中的serving.py。

def run_simple(
    hostname,
    port,
    application
):
    def inner():
        try:
            fd = int(os.environ["WERKZEUG_SERVER_FD"])
        except (LookupError, ValueError):
            fd = None
        srv = make_server(
            hostname,
            port,
            application,
            threaded,
            processes,
            request_handler,
            passthrough_errors,
            ssl_context,
            fd=fd,
        )
        if fd is None:
            log_startup(srv.socket)
        srv.serve_forever()
    inner()

run_simple()主要是執行了inner(),inner中初始化srv實例後執行srv.serve_forever()方法。先看make_server()方法,根據進程和線程使用不同的類進行初始化,且這些類都繼承了BaseWSGIServer。

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(省略 )   
    elif processes > 1:
        return ForkingWSGIServer(省略 )
    else: 
        return BaseWSGIServer(省略 )

這裏以BaseWSGIServer爲例進行分析。BaseWSGIServer繼承HTTPServer,這裏帶入的參數除了host,port還有handler,sWSGIRequestHandler,WSGIRequestHandler繼承BaseHTTPRequestHandler。主要是爲了實現http的數據請求和發送。

class BaseWSGIServer(HTTPServer, object):    """Simple single-threaded, single-process WSGI server."""    
    multithread = False    
    multiprocess = False
    def __init__(    
        self, 
        host,
        port,
        app,
        handler=None, 
        passthrough_errors=False,
        ssl_context=None, 
        fd=None,):
        if handler is None: 
            handler = WSGIRequestHandler

先看一下執行函數,serve_forever,執行的是 HTTPServer.serve_forever()

def serve_forever(self): 
    self.shutdown_signal = False
    try:       
        HTTPServer.serve_forever(self)
    except KeyboardInterrupt: 
        pass
    finally:
        self.server_close()

爲了更好的說明,把WSGIRequestHandler和BaseWSGIServer繼承過來,單獨運行獲得http的響應。

from werkzeug.serving import WSGIRequestHandler,BaseWSGIServer

class New_Handler(WSGIRequestHandler):
    page = '''\
               <html>
               <body>
               <p>hello</p>
               </body>
               </html>
               '''

    def do_GET(self):
        current_path = self.path
        # self.send_error(415,'your url is %s' % current_path)
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header("Content-Length", 100)
        self.end_headers()
        self.wfile.write(self.page.encode('utf-8'))

tcp_server = BaseWSGIServer(host="127.0.0.1",port=5000,app=None,handler=New_Handler)

if __name__ == "__main__":
    tcp_server.serve_forever()

既然http的請求響應入口已經找到了,那麼就來看看請求路由的處理,所以要研究裝飾器@app.route('/'),來看看Flask中路由處理思路。
裝飾器如下:

def route(self, rule, **options):
    def decorator(f):
        endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f
    return decorator

# 路由裝飾器的使用
@app.route('/')
def hello_world():
    return "hello_world"

以簡單根目錄請求爲例,通過裝飾器可以看出,首先執行self.add_url_rule(rule, endpoint, f, **options),然後再執行實例方法hello_world()。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章