文章转载自https://blog.csdn.net/weixin_37923128/article/details/80992645 , 感谢原作者
当客户端向服务器发送一个请求时,服务器会将请求转发给web应用程序,应用程序处理完这个请求后将会返回一个response。在这篇文章我们分析一下flask怎样处理request,又是怎样生成response的,同时我们应该思考,在这个过程中,flask是怎样让url、endpoint、视图函数一一对应的。
一旦web应用接收到request,flask就会调用Flask类的call函数。在wsgi_app()函数中,我们看到,在调用了full_dispatch_request()函数后,就生成了response(Response类实例)。
1 class Flask: 2 def __call__(self, environ, start_response): 3 return self.wsgi_app(environ, start_response) 4 5 def wsgi_app(self, environ, start_response): 6 ctx = self.request_context(environ) 7 error = None 8 try: 9 try: 10 ctx.push() 11 response = self.full_dispatch_request() 12 except Exception as e: 13 error = e 14 response = self.handle_exception(e) 15 except: 16 error = sys.exc_info()[1] 17 raise 18 return response(environ, start_response) 19 finally: 20 if self.should_ignore_error(error): 21 error = None 22 ctx.auto_pop(error)
在函数full_dispatch_request中,我们看到了dispatch_request函数,一路寻找下去,在这个函数里找到了view_functions这个字典。这个字典被多个函数在多个函数中出现。
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) 11 12 def dispatch_request(self): 13 req = _request_ctx_stack.top.request 14 if req.routing_exception is not None: 15 self.raise_routing_exception(req) 16 rule = req.url_rule 17 18 if getattr(rule, 'provide_automatic_options', False) 19 and req.method == 'OPTIONS': 20 return self.make_default_options_response() 21 return self.view_functions[rule.endpoint](**req.view_args) 22 23 self.view_functions = {}
那这个add_url_rule函数又是在哪里被调用的呢?往下看。
1 def add_url_rule(self, rule, endpoint=None, view_func=None,provide_automatic_options=None, **options): 2 if endpoint is None: 3 endpoint = _endpoint_from_view_func(view_func) 4 options['endpoint'] = endpoint 5 methods = options.pop('methods', None) 6 7 # if the methods are not given and the view_func object knows its 8 # methods we can use that instead. If neither exists, we go with 9 # a tuple of only ``GET`` as default. 10 if methods is None: 11 methods = getattr(view_func, 'methods', None) or ('GET',) 12 if isinstance(methods, string_types): 13 raise TypeError('Allowed methods have to be iterables of strings, ''for example: @app.route(..., methods=["POST"])') 14 methods = set(item.upper() for item in methods) 15 16 # Methods that should always be added 17 required_methods = set(getattr(view_func, 'required_methods', ())) 18 19 # starting with Flask 0.8 the view_func object can disable and 20 # force-enable the automatic options handling. 21 if provide_automatic_options is None: 22 provide_automatic_options = getattr(view_func,'provide_automatic_options', None) 23 24 if provide_automatic_options is None: 25 if 'OPTIONS' not in methods: 26 provide_automatic_options = True 27 required_methods.add('OPTIONS') 28 else: 29 provide_automatic_options = False 30 31 # Add the required methods now. 32 methods |= required_methods 33 34 rule = self.url_rule_class(rule, methods=methods, **options) 35 rule.provide_automatic_options = provide_automatic_options 36 37 self.url_map.add(rule) 38 if view_func is not None: 39 old_func = self.view_functions.get(endpoint) 40 if old_func is not None and old_func != view_func: 41 raise AssertionError('View function mapping is overwriting an ''existing endpoint function: %s' % endpoint) 42 self.view_functions[endpoint] = view_func
看到这里就应该明白了。在我们写的web应用程序中,往往需要对视图函数添加路由修饰,如:app.route(‘/’)。正是在路由函数中调用了add_url_rule函数,而这个函数负责绑定相应的视图函数、url、以及endpoint。由此,这三个参数建立联系。而后,在程序运行中,当web程序收到请求后,根据请求中的url找到endpoint,再根据endpoint找到视图函数,然后调用视图函数,在视图函数中,会处理那些需要处理的值(return self.view_functionsrule.endpoint)。接下来这个函数的返回值会交给finalize_request()函数处理。
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
正是在这个函数里,生成了response。(response是Response类的实例),最终,这个response被返回给客户端,然后显示为页面。
1 def finalize_request(self, rv, from_error_handler=False): 2 response = self.make_response(rv) 3 try: 4 response = self.process_response(response) 5 request_finished.send(self, response=response) 6 except Exception: 7 if not from_error_handler: 8 raise 9 self.logger.exception('Request finalizing failed with an ''error while handling an error') 10 return response