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来实例化出来的
原文:https://www.cnblogs.com/cx59244405/p/11451010.html