Flask启动原理,源码流程分析

1.执行Flask的实例对象.run()方法

from flask import Flask,request,session

app = Flask(__name__)


app.secret_key ='sdfsdfsdf'


if __name__ == '__main__':
    app.__call__
    app.run()


2.经过对IP与端口的处理,然后执行 from werkzeug.serving import run_simple中的 run_simple(host, port, self, **options)方法

    def run(self, host=None, port=None, debug=None, **options):
       
        from werkzeug.serving import run_simple
        #查看是否有ip
        if host is None:
            host = '127.0.0.1'
        if port is None:
            # 读取settings文件
            server_name = self.config['SERVER_NAME']
            # print(server_name)#127.0.0.1:80
            if server_name and ':' in server_name:
                port = int(server_name.rsplit(':', 1)[1])
                # print(port)#80
            else:
                port = 5000
        if debug is not None:
            self.debug = bool(debug)
            print(self.debug)
        options.setdefault('use_reloader', self.debug)
        options.setdefault('use_debugger', self.debug)
        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
def run_simple(hostname, port, application, use_reloader=False,
               use_debugger=False, use_evalex=True,
               extra_files=None, reloader_interval=1,
               reloader_type='auto', threaded=False,
               processes=1, request_handler=None, static_files=None,
               passthrough_errors=False, ssl_context=None):
    """Start a WSGI application. Optional features include a reloader,
    multithreading and fork support.

    This function has a command-line interface too::

        python -m werkzeug.serving --help

    .. versionadded:: 0.5
       `static_files` was added to simplify serving of static files as well
       as `passthrough_errors`.

    .. versionadded:: 0.6
       support for SSL was added.

    .. versionadded:: 0.8
       Added support for automatically loading a SSL context from certificate
       file and private key.

    .. versionadded:: 0.9
       Added command-line interface.

    .. versionadded:: 0.10
       Improved the reloader and added support for changing the backend
       through the `reloader_type` parameter.  See :ref:`reloader`
       for more information.

    :param hostname: The host for the application.  eg: ``'localhost'``
    :param port: The port for the server.  eg: ``8080``
    :param application: the WSGI application to execute
    :param use_reloader: should the server automatically restart the python
                         process if modules were changed?
    :param use_debugger: should the werkzeug debugging system be used?
    :param use_evalex: should the exception evaluation feature be enabled?
    :param extra_files: a list of files the reloader should watch
                        additionally to the modules.  For example configuration
                        files.
    :param reloader_interval: the interval for the reloader in seconds.
    :param reloader_type: the type of reloader to use.  The default is
                          auto detection.  Valid values are ``'stat'`` and
                          ``'watchdog'``. See :ref:`reloader` for more
                          information.
    :param threaded: should the process handle each request in a separate
                     thread?
    :param processes: if greater than 1 then handle each request in a new process
                      up to this maximum number of concurrent processes.
    :param request_handler: optional parameter that can be used to replace
                            the default one.  You can use this to replace it
                            with a different
                            :class:`~BaseHTTPServer.BaseHTTPRequestHandler`
                            subclass.
    :param static_files: a list or dict of paths for static files.  This works
                         exactly like :class:`SharedDataMiddleware`, it's actually
                         just wrapping the application in that middleware before
                         serving.
    :param passthrough_errors: set this to `True` to disable the error catching.
                               This means that the server will die on errors but
                               it can be useful to hook debuggers in (pdb etc.)
    :param ssl_context: an SSL context for the connection. Either an
                        :class:`ssl.SSLContext`, a tuple in the form
                        ``(cert_file, pkey_file)``, the string ``'adhoc'`` if
                        the server should automatically create one, or ``None``
                        to disable SSL (which is the default).
    """


3.execute(app) 中 application_iter = app(environ, start_response)即call方法

        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


4.call方法中返回 return self.wsgi_app(environ, start_response)

def __call__(self, environ, start_response):
"""Shortcut for :attr:`wsgi_app`."""
print(environ,start_response)

return self.wsgi_app(environ, start_response)


5.首先,处理的是request和session,将请求添加到Local中,即 ctx = self.request_context(environ)

    def wsgi_app(self, environ, start_response):
        
        #处理request,将请求添加到local中
        ctx = self.request_context(environ)
        # 处理request和session
        ctx.push()
        error = None
        try:
            try:
                # 执行视图函数
                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
            ctx.auto_pop(error)


5.1.返回的是 return RequestContext(self, environ) 即类的一个实例

    def request_context(self, environ):
        
        return RequestContext(self, environ)


5.2.执行 ctx.push()方法 保存

    def push(self):
        """Binds the request context to the current context."""
        
        top = _request_ctx_stack.top
        if top is not None and top.preserved:
            top.pop(top._preserved_exc)

        # Before we push the request context we have to ensure that there
        # is an application context.
        app_ctx = _app_ctx_stack.top
        if app_ctx is None or app_ctx.app != self.app:
            app_ctx = self.app.app_context()
            app_ctx.push()
            self._implicit_app_ctx_stack.append(app_ctx)
        else:
            self._implicit_app_ctx_stack.append(None)

        if hasattr(sys, 'exc_clear'):
            sys.exc_clear()

        _request_ctx_stack.push(self)

       
        self.session = self.app.open_session(self.request)
        if self.session is None:
            self.session = self.app.make_null_session()


6.执行视图函数 response = self.full_dispatch_request()方法

    def full_dispatch_request(self):
        """Dispatches the request and on top of that performs request
        pre and postprocessing as well as HTTP exception catching and
        error handling.

        .. versionadded:: 0.7
        """
        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)


6.1:执行 self.try_trigger_before_first_request_functions()即装饰器@before_first_request装饰所有函数
6.2:执行 rv = self.preprocess_request()方法 即@before_request装饰所有函数
6.3:return self.finalize_request(rv)方法 即@after_request装饰所有函数
response = self.process_response(response)方法
# 执行after_request 装饰所有的函数 response = handler(response)
最后处理session self.save_session(ctx.session, response)

7.return response(environ, start_response) 将处理完的内容返回给用户浏览器

原文地址:https://www.cnblogs.com/ldq1996/p/8244552.html