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