您好,登錄后才能下訂單哦!
Python基礎(chǔ)教程:Flask進(jìn)擊篇——Flask運(yùn)行流程
在我們了解Flask運(yùn)行流程之前,先看一下我們?cè)跒g覽器一次請(qǐng)求中所經(jīng)歷的過(guò)程,下面這張是結(jié)合Flask的源碼繪制的一張流程圖
能看到Flask在一次請(qǐng)求中實(shí)際上只是做了最后一部分功能,這里沒有將Flask的具體處理流程列出來(lái),我們?cè)谙旅鏁?huì)繼續(xù)講解。
在上圖中出現(xiàn)WSGIRequestHandler,WSGI協(xié)議是在Python Web開發(fā)中很核心的部分,如果想繼續(xù)進(jìn)擊的話,需要對(duì)這部分有深刻的理解。
這部分我在前面的 Python基礎(chǔ)教程有講到過(guò)!
我所理解Flask要做的事情,是根據(jù)請(qǐng)求的HTTP協(xié)議中url和method映射相應(yīng)的處理函數(shù),處理完并返回。這是基礎(chǔ)的功能,F(xiàn)lask在這基礎(chǔ)上又增加了一些其他功能。下面我們就通過(guò)Flask的源碼中一些屬性來(lái)進(jìn)行分析。
Flask在啟動(dòng)時(shí)已將各屬性根據(jù)需求配置好,但實(shí)際映射函數(shù)的屬性就是view_functions,此屬性類型為字典,key是endpoint。
endpoint可自定義,若不指定將會(huì)根據(jù)函數(shù)名生成,若出現(xiàn)重復(fù)的endpoint將會(huì)提示錯(cuò)誤。
endpoint會(huì)與url和method統(tǒng)一封裝成到rule放入到url_map中,在請(qǐng)求過(guò)來(lái)時(shí)會(huì)根據(jù)url和和method生成reuqest到url_map中匹配,如果匹配到則根據(jù)endpoint獲取到相應(yīng)的函數(shù)去執(zhí)行,并將結(jié)果返回。這部分可以看Flask源碼部分。
添加到url_map
# flask/app.py def add_url_rule( self, rule, endpoint=None, view_func=None, provide_automatic_options=None, **options ): if endpoint is None: endpoint = _endpoint_from_view_func(view_func) options["endpoint"] = endpoint methods = options.pop("methods", None) if methods is None: methods = getattr(view_func, "methods", None) or ("GET",) if isinstance(methods, string_types): raise TypeError( "Allowed methods have to be iterables of strings, " 'for example: @app.route(..., methods=["POST"])' ) methods = set(item.upper() for item in methods) # Methods that should always be added required_methods = set(getattr(view_func, "required_methods", ())) # starting with Flask 0.8 the view_func object can disable and # force-enable the automatic options handling. if provide_automatic_options is None: provide_automatic_options = getattr( view_func, "provide_automatic_options", None ) if provide_automatic_options is None: if "OPTIONS" not in methods: provide_automatic_options = True required_methods.add("OPTIONS") else: provide_automatic_options = False # Add the required methods now. methods |= required_methods rule = self.url_rule_class(rule, methods=methods, **options) rule.provide_automatic_options = provide_automatic_options self.url_map.add(rule) if view_func is not None: old_func = self.view_functions.get(endpoint) if old_func is not None and old_func != view_func: raise AssertionError( "View function mapping is overwriting an " "existing endpoint function: %s" % endpoint ) self.view_functions[endpoint] = view_func
請(qǐng)求時(shí)匹配請(qǐng)求
1.生成請(qǐng)求
# flask/app.py def create_url_adapter(self, request): if request is not None: subdomain = ( (self.url_map.default_subdomain or None) if not self.subdomain_matching else None ) return self.url_map.bind_to_environ( request.environ, server_name=self.config["SERVER_NAME"], subdomain=subdomain, ) if self.config["SERVER_NAME"] is not None: return self.url_map.bind( self.config["SERVER_NAME"], script_name=self.config["APPLICATION_ROOT"], url_scheme=self.config["PREFERRED_URL_SCHEME"], ) # flask/ctx.py def match_request(self): try: result = self.url_adapter.match(return_rule=True) self.request.url_rule, self.request.view_args = result except HTTPException as e: self.request.routing_exception = e
此處是在生成上下文的push中執(zhí)行會(huì)執(zhí)行match_request,這里沒有貼出來(lái)。
實(shí)質(zhì)就是請(qǐng)求過(guò)來(lái)了,根據(jù)url和method匹配啟動(dòng)時(shí)的url_map,如果沒有的話則返回匹配不到
2.匹配請(qǐng)求
# flask/app.py def dispatch_request(self): req = _request_ctx_stack.top.request if req.routing_exception is not None: self.raise_routing_exception(req) rule = req.url_rule if ( getattr(rule, "provide_automatic_options", False) and req.method == "OPTIONS" ): return self.make_default_options_response() # otherwise dispatch to the handler for that endpoint return self.view_functions[rule.endpoint](**req.view_args)
根據(jù)上面從url_map得到的rule,然后根據(jù)endpoint取得要執(zhí)行的函數(shù)。
Flask另外幾個(gè)屬性,則表示在請(qǐng)求之前和請(qǐng)求之后做一些處理,并且可以針對(duì)不同的blueprints來(lái)進(jìn)行處理,關(guān)于blueprints我們等幾個(gè)章節(jié)再細(xì)分析。
Flask實(shí)際的處理流程是什么樣子,先看一下Flask的源碼
# flask/app.py # 1. 先通過(guò)wsgi協(xié)議到這個(gè)函數(shù) def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response) # 2. 然后調(diào)用這個(gè)函數(shù),處理上下文 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. 請(qǐng)求處理流程 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)
基本流程可以看的比較清晰,至于每個(gè)函數(shù)列表的來(lái)源以及作用,我在開始的屬性圖上已將其標(biāo)識(shí)出來(lái)。
至此可以大體知道請(qǐng)求過(guò)來(lái)之后Flask是如何處理及前期Flask會(huì)構(gòu)建哪些內(nèi)容。
但Flask還有很多東西。例如我們經(jīng)常使用request,current_app對(duì)象和常用的blueprints是怎么個(gè)原理。
更多的 Python基礎(chǔ)教程也會(huì)繼續(xù)為大家更新!大家有什么想學(xué)的內(nèi)容也可以留言或者私信我,人多的話,可以考慮出一期!最近也整理了一些Python基礎(chǔ)教程學(xué)習(xí)的視頻,有需要的伙伴可以留言私信我回復(fù)Python,僅30份!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。