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)

视图函数: 格式-----

self.view_functions = {}

加载所有的@app.before_request的函数,格式

self.before_request_funcs = {}

加载所有的@before_first_request的函数,格式[func3, func4...]

self.before_first_request_funcs = []

加载所有的@app.after_request的函数,格式

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的函数,格式

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的函数,格式

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 =

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

posted @ 2019-11-25 17:51  阿浪阿浪  阅读(496)  评论(0)    收藏  举报