zoukankan      html  css  js  c++  java
  • Flask源码分析一:服务启动

    前言

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

    Flask系列文章:

    1. Flask开发初探

    正文

    本文将结合源码跟踪看下Flask是如何启动并运行一个服务的。在0.11版本以后,支持命令行启动flask。

    目前共有两种方式可以载入应用:

    1. python app.py

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

    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'Hello Flask!'
    
    if __name__ == '__main__':
        app.run()
    

    执行python app.py即可启动。

    我们看到,这段代码先初始化了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 从项目根目录下的.flaskenv.env文件中导入环境变量

    该方法的处理流程是:对入参进行配置处理之后,执行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:

    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
    

    2. Flask命令

    接下来我们通过flask命令来启动一个应用,hello.py:

    from flask import Flask
    app = Flask(__name__)
    
    @app.route('/')
    def hello_world():
        return 'Hello Flask!'
    

    Unix Bash ( Linux 、Mac 及其他):

    $ export FLASK_APP=hello
    $ flask run
    

    这样便启动了该 应用,那么内部的实现机理是怎样的呢?

    1. 设置环境变量Flask_APP,指定应用的路径
    2. 通过run命令来启动开发服务器,其中flask命令是由Flask安装的。

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

  • 相关阅读:
    ci中使用smarty
    php curl用法
    百万级访问网站前期的技术准备
    enctype="multipart/formdata" 文件上传
    【转】lnmp配置记录
    ActionScript实现两直线相交弧跨越算法
    Adobe Flex迷你教程 — ActionScript实现二维向量运算
    U盘启动安装Linux(转)
    Adobe Flex迷你教程 — 实现类似新浪微博评论消息容器
    Adobe Flex迷你教程 — 让Graphics的线响应事件。
  • 原文地址:https://www.cnblogs.com/ybjourney/p/11717347.html
Copyright © 2011-2022 走看看