Flask源码分析(二)Flask是如何处理请求的?上次提到了Flask的__call__方法,当请求到来时会调用该方法。传入的参数是environ和start_response。environ其实就是请求头的一些参数,包括协议号、请求方法、请求路径等参数(可以在WSGIRequestHandler的make_response方法中查看)。而start_response是对responseheader的处理函数,这里引用这个函数。classFlask(_PackageBoundObject):def__call__(self,environ,start_response):"""WSGI服务器调用Flask应用程序对象作为WSGI应用程序。这调用:meth:`wsgi_app`可以包装到应用中间件。"""返回self.wsgi_app(environ,start_response)classWSGIRequestHandler(BaseHTTPRequestHandler,object):defmake_environ(self):request_url=url_parse(self.path)environ={"wsgi.version":(1,0),"wsgi.url_scheme":url_scheme,"wsgi.input":self.rfile,"wsgi.errors":sys.stderr,"wsgi.multithread":self.server.multithread,"wsgi.multiprocess":self.server.multiprocess,"wsgi.run_once”:假,“werkzeug.server.shutdown”:shutdown_server,“SERVER_SOFTWARE”:self.server_version,“REQUEST_METHOD”:self.command,“SCRIPT_NAME”:“”,“PATH_INFO”:wsgi_encoding_dance(path_info),"QUERY_STRING":wsgi_encoding_dance(request_url.query),#非标准,由mod_wsgi添加,uWSGI"REQUEST_URI":wsgi_encoding_dance(self.path),#非标准,由gunicorn添加"RAW_URI":wsgi_encoding_dance(self.path),“REMOTE_ADDR”:self.address_string(),“REMOTE_PORT”:self.port_integer(),“SERVER_NAME”:self.server.server_address[0],“SERVER_PORT”:str(self.server.server_address[1]),"SERVER_PROTOCOL":self.request_version,}returnenvirondefstart_response(status,response_headers,exc_info=None):ifexc_info:try:ifheaders_sent:reraise(*exc_info)最后:exc_info=Noneelifheaders_set:raiseAssertionError("Headersalreadyset")headers_set[:]=[status,response_headers]returnwrite2.来看__call__方法接收这两个参数后执行了什么所以__call__返回自己的wsgi_app方法,请求的所有处理都在这个方法中。self.request_context是创建当前请求的上下文环境,下篇文章再详细说。关键在于self.full_dispatch_request方法,在这里深入挖掘。defwsgi_app(self,environ,start_response):ctx=self.request_context(environ)#创建当前请求的上下文error=Nonetry:try:ctx.push()response=self.full_dispatch_request()exceptExceptionase:error=eresponse=self.handle_exception(e)除了:#noqa:B001error=sys.exc_info()[1]raisereturnresponse(environ,start_response)finally:ifself.should_ignore_error(error):error=Nonectx.auto_pop(error)3.self.full_dispatch_request*是派发请求,并在其之上执行请求的前处理和后处理,以及HTTP异常捕获和错误处理。其实就是执行相应的视图函数。在这里深入挖掘,您可以看到执行流程。当请求到来时,首先进行预处理,即在进入视图函数之前,先执行@app.before_first_request、@app.before_request等装饰器中的代码。也可以看出,如果有多个预处理函数,如果第一个有返回值,那么只会执行第一个,也就是较高的那个,而不会执行请求url对应的视图函数被执行。预处理完成后,会将返回内容交给self.make_response方法处理,构造返回内容。然后是后期处理。后处理会执行所有被@after_request修饰的后处理函数,每个后处理函数都必须接受response参数并返回,因为response在这里是一层层处理的。而且,执行和预处理的顺序是相反的,自下而上。deffull_dispatch_request(self):self.try_trigger_before_first_request_functions()try:request_started.send(self)rv=self.preprocess_request()#进行预处理ifrvisNone:rv=self.dispatch_request()exceptExceptionase:rv=self.handle_user_exception(e)returnself.finalize_request(rv)#处理defpreprocess_request(self):'''处理'''bp=_request_ctx_stack.top.request.blueprintfuncs=self.url_value_preprocessors.get(None,())如果bp不是None并且bp在self.url_value_preprocessors中:,())如果bp不是None并且bp在self.before_request_funcs中:ze_request(self,rv,from_error_handler=False):'''后处理并返回response'''response=self.make_response(rv)#这里涉及到调用start_response那个数了try:response=self.process_response(response)#处理request_finished.send(self,response=response)exceptException:ifnotfrom_error_handler:raiseself.logger.exception("Requestfinalizingfailedwithanerrorwhilehandlinganerror")returnrespondefprocess_response(self,response):'''后处理'''ctx=_request_ctx_stack.topbp=ctx.request.blueprintfuncs=ctx._after_request_functions如果bp不是None并且bp在self.after_request_funcs:funcs=chain(funcs,reversed(self.after_request_funcs[bp]))如果在self.after_request_funcs中没有:funcs=chain(funcs,reversed(self.after_request_funcs[None]))forhandlerinfuncs:response=handler(response)ifnotself.session_interface.is_null_session(ctx.session):self.session_interface.save_session(self,ctx.session,response)返回response4。以上就是flask的请求处理逻辑,那么一开始传入的start_response函数是在哪里调用的呢?答案是上面提到的Flask中定义的wigi_app方法中有一句话:returnresponse(environ,start_response)。这个response其实就是BaseResponse类实例化的对象,对象+()只是调用了它的__call__方法,然后再去它的__call__方法看。果然,这里终于调用了start_response。classFlask(_PackageBoundObject):#...#response_class即Response这个类response_class=Response#...defmake_response(self,rv):#...#如果不是isinstance,确保body是响应类的一个实例(rv,self.response_class):ifisinstance(rv,(text_type,bytes,bytearray)):#让响应类设置状态和标头,而不是#等待手动执行,以便该类可以处理任何#特殊logic#这里返回了response_class类的实例化对象rv=self.response_class(rv,status=status,headers=headers)status=headers=None#...returnrvclassResponse(ResponseBase,JSONMixin):"""Response继承自ResponseBase,继续深入挖掘"""passclassResponse(BaseResponse,ETagResponseMixin,WWWAuthenticateMixin,CORSResponseMixin,ResponseStreamMixin,CommonResponseDescriptorsMixin,):#Response继承自BaseResponsepassclassBaseResponse(object):def__init__(self,response=None,status=None,headers=None,mimetype=None,content_type=None,direct_passthrough=False,):passdef__call__(self,environ,start_response):#果然,就在这里!案例解决app_iter,status,headers=self.get_wsgi_response(environ)start_response(status,headers)returnapp_iter
