首页 > 其他 > 详细

Flask运行原理

时间:2019-09-03 11:03:11      阅读:144      评论:0      收藏:0      [点我收藏+]

0、写在前面

通过阅读Flask的源码来学习下运行原理

1、启动,从请求到响应的过程

一个最简单的程序HelloWrold.py

 1 from flask import Flask
 2 
 3 app = Flask(__name__)
 4 
 5 @app.route(/)
 6 def hello_world():
 7     return Hello World!
 8 
 9 if __name__ == __main__:
10     app.run()

可以看到,主要运行服务的代码只有2行

实例化 app = Flask(__name__)

运行 app.run()

实例化FLASK后,运行其中的run函数

run函数中的代码,传入一些配置参数后,实际运行的是werkzeug.serving.run_simple(host, port, self, **options)

Flask的底层运行的服务实际是调用werkzeug.serving.run_simple()后做了一些封装

run_simple()传入的self就是app,而且会以app()的形式运行

app()相当于执行app.__call__()

 1     def run(self, host=None, port=None, debug=None,
 2             load_dotenv=True, **options):
 3         from werkzeug.serving import run_simple
 4 
 5         try:
 6             run_simple(host, port, self, **options)
 7         finally:
 8             self._got_first_request = False

app.__call__(),执行了一行self.wsgi_app(environ, start_response)

按照wsgi协议,

environ:一个包含所有HTTP请求信息的dict对象

start_response:一个发送HTTP响应的函数

1     def __call__(self, environ, start_response):
2         return self.wsgi_app(environ, start_response)

environ被经过一系列封装处理后,最终返回了封装了request和session的Request类的对象,赋值给ctx

这个ctx即为请求上下文,下文中再说 

最后返回response(environ, start_response)

 1     def wsgi_app(self, environ, start_response):
 2         ctx = self.request_context(environ)
 3         error = None
 4         try:
 5             try:
 6                 ctx.push()
 7                 response = self.full_dispatch_request()
 8             except Exception as e:
 9                 error = e
10                 response = self.handle_exception(e)
11             except:
12                 error = sys.exc_info()[1]
13                 raise
14             return response(environ, start_response)
15         finally:
16             if self.should_ignore_error(error):
17                 error = None
18             ctx.auto_pop(error)

然后进入full_dispatch_request(self)

执行 self.try_trigger_before_first_request_functions()即装饰器@before_first_request装饰所有函数

执行 rv = self.preprocess_request()方法 即@before_request装饰所有函数

return self.finalize_request(rv)方法 即@after_request装饰所有函数

进入self.finalize_request(rv),response = self.process_response(response)

 1     def full_dispatch_request(self):
 2         self.try_trigger_before_first_request_functions()
 3         try:
 4             request_started.send(self)
 5             rv = self.preprocess_request()
 6             if rv is None:
 7                 rv = self.dispatch_request()
 8         except Exception as e:
 9             rv = self.handle_user_exception(e)
10         return self.finalize_request(rv)

从请求上下文栈中取出request,进行路由匹配,执行视图函数

1     def dispatch_request(self):
2         req = _request_ctx_stack.top.request
3         if req.routing_exception is not None:
4             self.raise_routing_exception(req)
5         rule = req.url_rule
6         if getattr(rule, provide_automatic_options, False) 7            and req.method == OPTIONS:
8             return self.make_default_options_response()
9         return self.view_functions[rule.endpoint](**req.view_args)

 

2、路由

通过HelloWrold.py可以看到路由是通过一个装饰器@app.route(‘/‘)添加进来的

找个装饰器实际运行的代码self.add_url_rule(rule, endpoint, f, **options)

1     def route(self, rule, **options):
2         def decorator(f):
3             endpoint = options.pop(endpoint, None)
4             self.add_url_rule(rule, endpoint, f, **options)
5             return f
6         return decorator

endpoint是路由的唯一标识,如果为空,则把函数名赋值给endpoint

实际添加路由的self.url_map.add(rule),该函数来自于self.url_map= werkzeug.routing.Map(),在这里进行路由的添加

路由分发上文中有

 1     @setupmethod
 2     def add_url_rule(self, rule, endpoint=None, view_func=None,
 3         if endpoint is None:
 4             endpoint = _endpoint_from_view_func(view_func)
 5         options[endpoint] = endpoint
 6         methods = options.pop(methods, None)
 7 
 8         rule = self.url_rule_class(rule, methods=methods, **options)
 9         rule.provide_automatic_options = provide_automatic_options
10 
11         self.url_map.add(rule)
12         if view_func is not None:
13             old_func = self.view_functions.get(endpoint)
14             if old_func is not None and old_func != view_func:
15                 raise AssertionError(View function mapping is overwriting an 
16                                      existing endpoint function: %s % endpoint)
17             self.view_functions[endpoint] = view_func

 

3、本地上下文

FLask上下文包含两种,请求上下文、程序上下文,原理相同。

包括全局变量request、session、current_app、g

都是通过本地代理LocalProxy来实例化出来的

 

Flask运行原理

原文:https://www.cnblogs.com/cx59244405/p/11451010.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!