• flask启动流程01


    flask 源码分析01:启动流程

    1.WSGI简介

    '''
    
    Flask框架遵循wsgi协议
    
    1.	WSGI 中有一个非常重要的概念:每个 python web 应用都是一个可调用(callable)的对象。在 flask 中,这个对象就是 app = Flask(__name__) 创建出来的 app
    
    2.	要运行 web 应用,必须有 web server,比如我们熟悉的 apache、nginx ,或者 python 中的 gunicorn,
    flask框架则应用到了werkzeug工具包提供的WSGIServer,监听在指定的端口,收到 HTTP 请求的时候解析为 WSGI 格式,然后调用 app 去执行处理的逻辑。
    
    3. Server 和 Application 之间怎么通信,就是 WSGI 的功能。它规定了 app(environ, start_response) 的接口,server 会调用 application,并传给它两个参数:environ 包含了请求的所有信息,start_response 是 application 处理完之后需要调用的函数,参数是状态码、响应头部还有错误信息。
    
    
    4. WSGI application 非常重要的特点是:它是可以嵌套的。换句话说,我可以写个 application,它做的事情就是调用另外一个 application,然后再返回(类似一个 proxy)。一般来说,嵌套的最后一层是业务应用,中间就是 middleware。这样的好处是,可以解耦业务逻辑和其他功能,比如限流、认证、序列化等都实现成不同的中间层,不同的中间层和业务逻辑是不相关的,可以独立维护;而且用户也可以动态地组合不同的中间层来满足不同的需求。
    
    '''
    

    2.实例化flask对象

    from flask import Flask
    app = Flask(__name__)
    

    2.1静态属性

    class Flask(object):
    
    	# 请求响应
    	request_class = Request
    	response_class = Response
    	
    	# 配置文件
    	config_class = Config
    	
    	# 秘钥
    	secret_key = ConfigAttribute("SECRET_KEY")
    	
    	# 路由
    	url_rule_class = Rule
    	url_map_class = Map
    	
    	# session
    	session_interface = SecureCookieSessionInterface()
    	
    	# 模板
    	template_folder = None
    

    2.2init初始化

    def __init__(self,...):
    
    	# 静态文件相关
    	self.static_url_path = static_url_path
    	self.static_folder = static_folder
    	
    	# 配置文件
    	self.config = self.make_config(instance_relative_config)
    	
    	# 视图函数: 格式-----{endpoint:func名}
    	self.view_functions = {}
    	
    	# 加载所有的@app.before_request的函数,格式{ None:[func1, func2...] }
    	self.before_request_funcs = {}
    	
    	# 加载所有的@before_first_request的函数,格式[func3, func4...]
    	self.before_first_request_funcs = []
    	
    	# 加载所有的@app.after_request的函数,格式{ None:[func1, func2...] }
    	self.after_request_funcs = {}
    	
    	# 蓝图
    	self.blueprints = {}
        self._blueprint_order = []
    	
    	# url
    	self.url_map = self.url_map_class()
    
    	# 添加静态文件路由
    	if self.has_static_folder:
            assert (
                bool(static_host) == host_matching
            ), "Invalid static_host/host_matching combination"
            self.add_url_rule(
                self.static_url_path + "/<path:filename>",
                endpoint="static",
                host=static_host,
                view_func=self.send_static_file,
            )
    

    3.秘钥处理

    '''
    app.secret_key = 'david'
    '''
    ......
    

    4.加载配置文件

    '''
    app.config.from_object(settings.py)
    '''
    
    class Config(dict):
    	
    	def from_object(self, obj):
    		if isinstance(obj, string_types):
    			obj = import_string(obj)
    			
    		# 遍历配置文件,并以键值对的形式存储
    		for key in dir(obj):
    			if key.isupper():
    				self[key] = getattr(obj, key)
    

    5.before_first_request

    '''
    @app.before_first_request
    def func3():
    	pass
    	
    @app.before_first_request
    def func4():
    	pass
    '''
    
    # 添加所有的@before_first_request的函数名到列表,格式[func3, func4...]
    # self.before_first_request_funcs = []
    @setupmethod
    def before_first_request(self, f):
        self.before_first_request_funcs.append(f)
        return f
    

    6.before_request

    '''
    @app.before_request
    def func1():
    	pass
    	
    @app.before_request
    def func2():
    	pass
    	
    '''
    
    # 加载所有的@app.before_request的函数,格式{ None:[func1, func2...] }
    # self.before_request_funcs = {}
    @setupmethod
    def before_request(self, f):
        self.before_request_funcs.setdefault(None, []).append(f)
        return f
    

    7.after_request

    '''
    @app.after_request
    def func5():
    	pass
    	
    @app.after_request
    def func6():
    	pass
    	
    '''
    
    # 加载所有的@app.before_request的函数,格式{ None:[func5, func6...] }
    # self.before_request_funcs = {}
    @setupmethod
    def after_request(self, f):
        self.after_request_funcs.setdefault(None, []).append(f)
        return f
    

    8.路由与视图

    '''
    @app.route('/index', methods=['GET', 'POST'], endpoint='index')
    def index():
    	pass
    	
    '''
    # rule : url
    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
    
    @setupmethod
    def add_url_rule(
        self,
        rule,
        endpoint=None,
        view_func=None,
        provide_automatic_options=None,
        **options
    ):
    
    # 以下都是add_url_rule()内容》》》》》
    

    8.1路由之endpoint

        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options["endpoint"] = endpoint
    

    8.2路由之methods,不写默认是'GET'

        methods = options.pop("methods", None)
    
        # if the methods are not given and the view_func object knows its
        # methods we can use that instead.  If neither exists, we go with
        # a tuple of only ``GET`` as default.
        if methods is None:
            methods = getattr(view_func, "methods", None) or ("GET",)
        if isinstance(methods, string_types):
            raise TypeError(
                "Allowed methods have to be iterables of strings, "
                'for example: @app.route(..., methods=["POST"])'
            )
        methods = set(item.upper() for item in methods)
    

    8.3路由之rule_map

    	'''
    	# 路由 werkzeug工具集提供的路由系统:werkzeug/routing.py(Rule, Map)
    	url_rule_class = Rule
    	url_map_class = Map
    	
    	self.url_map = self.url_map_class()
    	
    	# 视图函数: 格式----- view_functions = {endpoint:view_func}
    	self.view_functions = {}
    	
    	'''
    	
    	
        rule = self.url_rule_class(rule, methods=methods, **options)
    
        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError(
                    "View function mapping is overwriting an "
                    "existing endpoint function: %s" % endpoint
                )
            self.view_functions[endpoint] = view_func
    

    9.启动入口代码

    # 应用启动的入口代码就是app.run()
    from flask import Flask
    app = Flask(__name__)
     
    @app.route('/')
    def hello_world():
    	return 'Hello, World!'
     
    if __name__ == '__main__':
    	app.run()
    
    # werkzeug.serving的run_simple
    def run(self, host=None, port=None, debug=None, **options):
    """Runs the application on a local development server."""
    
    	from werkzeug.serving import run_simple
    
    	# 如果host 和 port 没有指定,设置 host 和 port 的默认值 127.0.0.1 和 5000
    	if host is None:
    		host = '127.0.0.1'
    	if port is None:
    		server_name = self.config['SERVER_NAME']
    		if server_name and ':' in server_name:
    			port = int(server_name.rsplit(':', 1)[1])
    		else:
    			port = 5000
     
    	# 调用 werkzeug.serving 模块的 run_simple 函数,传入收到的参数
    	# 注意第三个参数传进去的是 self,也就是要执行的 web application
    	try:
    		run_simple(host, port, self, **options)
    	finally:
    		self._got_first_request = False
    希望你眼眸有星辰,心中有山海,从此以梦为马,不负韶华
  • 相关阅读:
    (Go)11.九九乘法表示例
    (Go)10.流程控制示例
    (Go)09.指针赋值修改示例
    (Go)08.time示例
    (Go)07.strings与strconv的示例
    (Go)07.Go语言中strings和strconv包示例代码详解02
    (Go)06. Printf格式化输出、Scanf格式化输入详解
    kafka参数在线修改
    vs code golang代码自动补全
    JVM 方法区
  • 原文地址:https://www.cnblogs.com/daviddd/p/11929305.html
Copyright © 2020-2023  润新知