1.此次从上一篇文章Flask是如何运行起来的接着说。上一次提到了Flask的__call__方法,会在请求到来被调用。传入的参数为environ和start_response。environ其实就是请求头的一些参数,包括协议号、请求方法、请求路径等参数(能够在WSGIRequestHandler的make_response方法中查看)。而start_response便是对响应头的处理函数,这里是传入了这个函数的引用。python
class Flask(_PackageBoundObject): def __call__(self, environ, start_response): """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response)
class WSGIRequestHandler(BaseHTTPRequestHandler, object): def make_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": False, "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), # Non-standard, added by mod_wsgi, uWSGI "REQUEST_URI": wsgi_encoding_dance(self.path), # Non-standard, added by 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, } return environ
def start_response(status, response_headers, exc_info=None): if exc_info: try: if headers_sent: reraise(*exc_info) finally: exc_info = None elif headers_set: raise AssertionError("Headers already set") headers_set[:] = [status, response_headers] return write
2.来看__call__方法接收这两个参数后执行了什么。__call__返回了自身的wsgi_app方法,全部对请求的处理,都在这个方法里了。self.request_context是建立当前请求的上下文环境,下一篇文章再详细讲吧。关键在self.full_dispatch_request方法,这里深挖一下。flask
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) # 建立当前请求的上下文 error = None try: try: ctx.push() response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: # noqa: B001 error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
3.self.full_dispatch_request*就是调度请求,并在其之上执行请求的预处理和后处理以及HTTP异常捕获和错误处理,实际就是执行相应的视图函数。在此深挖,能够看出其中的执行流程。segmentfault
请求到来首先进行预处理,即进入视图函数以前,先执行@app.before_first_request、@app.before_request等装饰器内的代码。还能够看出,若是有多个预处理函数的话,若是第一个有返回值,那么只执行第一个,即比较靠上的那一个,也不执行与请求url相应的视图函数了。session
预处理结束,会将返回的内容交给self.make_response这个方法进行处理,构建出返回的内容。而后是后处理,后处理会执行全部被@after_request装饰的后处理函数,并且每一个后处理函数必须接受response参数,并返回,由于在这里response是被层层处理的。并且执行顺序和预处理是相反的,自下而上。app
def full_dispatch_request(self): self.try_trigger_before_first_request_functions() try: request_started.send(self) rv = self.preprocess_request() # 进行预处理 if rv is None: rv = self.dispatch_request() except Exception as e: rv = self.handle_user_exception(e) return self.finalize_request(rv) # 后处理 def preprocess_request(self): '''预处理''' bp = _request_ctx_stack.top.request.blueprint funcs = self.url_value_preprocessors.get(None, ()) if bp is not None and bp in self.url_value_preprocessors: funcs = chain(funcs, self.url_value_preprocessors[bp]) for func in funcs: func(request.endpoint, request.view_args) funcs = self.before_request_funcs.get(None, ()) if bp is not None and bp in self.before_request_funcs: funcs = chain(funcs, self.before_request_funcs[bp]) for func in funcs: rv = func() if rv is not None: return rv def finalize_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) except Exception: if not from_error_handler: raise self.logger.exception( "Request finalizing failed with an error while handling an error" ) return response def process_response(self, response): '''后处理''' ctx = _request_ctx_stack.top bp = ctx.request.blueprint funcs = ctx._after_request_functions if bp is not None and bp in self.after_request_funcs: funcs = chain(funcs, reversed(self.after_request_funcs[bp])) if None in self.after_request_funcs: funcs = chain(funcs, reversed(self.after_request_funcs[None])) for handler in funcs: response = handler(response) if not self.session_interface.is_null_session(ctx.session): self.session_interface.save_session(self, ctx.session, response) return response
4.以上就是flask的请求处理逻辑了,那么最开始传入的start_response函数是在哪里被调用的呢?答案是上面提到的Flask中定义的这个wigi_app方法。这个方法中有一句:return response(environ, start_response)。这个response实际就是BaseResponse类实例化的对象,而对象+()正是调用了它的__call__方法,而后到它的__call__方法中去看,果真,最终在这里调用了start_response。函数
class Flask(_PackageBoundObject): # ... # response_class即Response这个类 response_class = Response # ... def make_response(self, rv): # ... # make sure the body is an instance of the response class if not isinstance(rv, self.response_class): if isinstance(rv, (text_type, bytes, bytearray)): # let the response class set the status and headers instead of # waiting to do it manually, so that the class can handle any # special logic # 这里返回了response_class类的实例化对象 rv = self.response_class(rv, status=status, headers=headers) status = headers = None # ... return rv class Response(ResponseBase, JSONMixin): """Response继承自ResponseBase,继续深挖""" pass class Response( BaseResponse, ETagResponseMixin, WWWAuthenticateMixin, CORSResponseMixin, ResponseStreamMixin, CommonResponseDescriptorsMixin, ): # Response又继承自BaseResponse pass class BaseResponse(object): def __init__( self, response=None, status=None, headers=None, mimetype=None, content_type=None, direct_passthrough=False, ): pass def __call__(self, environ, start_response): # 果真,在这里!破案了 app_iter, status, headers = self.get_wsgi_response(environ) start_response(status, headers) return app_iter