參考文檔:https://blog.csdn.net/sinat_36651044/article/details/77532510
再完整一些的流程:
(1)命令行中python flaskapp.py 運行,flaskapp.py模塊糜值,逐行運行flaskapp.py中的代碼丰捷。
(2) app = Flask(name)實例化一個Flask 對象坯墨,name為當前模塊名。
(3) @app.route("/") 使用了裝飾器病往,和add_url_rule性質(zhì)一樣捣染。功能是添加endpoint( ‘/’)和view_func(’index’)的映射關(guān)系到view_functions字典中。
(4) if name == 'main': 保證當前模塊是被直接運行停巷,而不是被其他模塊導入耍攘,然后在運行之后的代碼。
(5) app.run(debug=True) 在本地服務(wù)器上運行flask 應(yīng)用畔勤,同時傳遞了debug=True參數(shù)蕾各。
(6) run(self, host=None, port=None, debug=None, **options),self就是實例化了的 app庆揪,運行run()之后式曲,會設(shè)置host = '127.0.0.1', port = 5000。
(7)run()方法中 run_simple(host, port, self, **options) 運行之后會創(chuàng)建一個本地服務(wù)器缸榛。
(8) 設(shè)置默認的_got_first_request = False吝羞,表明服務(wù)器還沒有收到客戶端的請求。
(9) run_simple()100多行内颗,那些提示消息(*Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 等)也是在run_simple()中設(shè)置的钧排。重要的是這么一句srv = make_server(...),在這兒創(chuàng)建了本地服務(wù)器均澳。
(10) 根據(jù)前面?zhèn)鬟f的參數(shù)恨溜,make_server(...)返回了一個單進程單線程的WSGI server,即BaseWSGIServer负懦。BaseWSGIServer繼承了HTTPServer筒捺;HTTPServer繼承了TCPServer柏腻;TCPServer繼承了BaseServer纸厉。不考慮細節(jié),就是創(chuàng)建了本地服務(wù)器五嫂,同時颗品,本地服務(wù)器已經(jīng)記錄了flaskapp信息。
(11) WSGI server的功能:監(jiān)聽指定的端口沃缘,收到 HTTP 請求的時候解析為 WSGI 格式躯枢,然后調(diào)用 app 去執(zhí)行處理的邏輯。
再看從客戶端輸入網(wǎng)址槐臀,到看到網(wǎng)頁響應(yīng)的過程:
(1) 客戶端發(fā)送請求到 WSGI server锄蹂,WSGI server使用call 方法來調(diào)用 app處理請求,call方法返回了wsgi_app(environ, start_response)水慨,即使用wsgi_app(self, environ, start_response) 處理請求并將處理結(jié)果返回到服務(wù)器得糜,再返回到客戶端敬扛。
(2) 從BaseWSGIServer中的定義開始看:
BaseWSGIServer中有行代碼是handler = WSGIRequestHandler,即收到客戶端的請求后朝抖,本地的 WSGI server使用WSGIRequestHandler來處理請求啥箭。
(3) WSGIRequestHandler 有個重要的方法是make_environ(self),返回一個environ字典治宣〖苯模可以創(chuàng)建一個供app 運行的環(huán)境。
(4) 然后看WSGIRequestHandler 中的 handle_one_request()方法侮邀。handle_one_request()中關(guān)鍵的run_wsgi()坏怪,看名字,運行wsgi豌拙。
(5) WSGIRequestHandler繼承自BaseHTTPRequestHandler陕悬;BaseHTTPRequestHandler繼承自StreamRequestHandler;StreamRequestHandler繼承自BaseRequestHandler按傅。
(6) 看wsgi內(nèi)部的第一個 if語句捉超,如果請求頭中'Expect'''中間有'100-continue',將'HTTP/1.1 100 Continue\r\n\r\n'寫入到wfile中唯绍。
- headers is an instance of email.message.Message (or a derived class) containing the header information;
- wfile is a file object open for writing.
(7) 不看中間的函數(shù)定義拼岳,到了最重要的一行execute(self.server.app),(創(chuàng)建WSGI server時將app作為參數(shù)傳遞并保存在了WSGI server中)這里調(diào)用app來處理客戶端請求况芒。
(8) WSGI中調(diào)用app 會使用到Flask中的call方法惜纸。
(9) 不看具體處理過程,WSGI server現(xiàn)在完成了接收用戶請求绝骚,調(diào)用flask 應(yīng)用來處理請求的過程耐版。
然后開始了真正處理一個請求的過程。
(1) 回到Flask類中看call方法:
call(self, environ, start_response) 压汪,這里的self 是flask應(yīng)用本身粪牲,即實例化的app,environ, start_response 由WSGI server 提供止剖。call最后會返回wsgi_app(environ, start_response)腺阳,即使用wsgi_app 來處理客戶端的請求。
(2) wsgi_app 中:
ctx = self.request_context(environ)首先將environ 封裝在了一個請求上下文變量ctx中穿香。請求上下文使用棧結(jié)構(gòu)存儲數(shù)據(jù)亭引,ctx.push() 將environ 壓棧放在棧頂。
(3) 關(guān)鍵的一行response = self.full_dispatch_request() 使用 full_dispatch_request() 處理請求皮获,隨后返回處理結(jié)果:return response(environ, start_response)焙蚓。
(4)full_dispatch_request() :
Dispatches the request and on top of that performs request pre and postprocessing as well as HTTP exception catching and error handling.
首先是self.try_trigger_before_first_request_functions()
init函數(shù)中設(shè)置了self._got_first_request = False,try_trigger_before_first_request_functions()的最后一行設(shè)置了self._got_first_request = True,表明要開始處理請求了购公。
不分析太多了赵哲,full_dispatch_request() 關(guān)鍵是調(diào)用dispatch_request() 做真實處理,最后返回finalize_request() 將處理結(jié)果變成真正的響應(yīng)君丁。
(5) dispatch_request():
Does the request dispatching. Matches the URL and returns the return value of the view or error handler. This does not have to be a response object. In order to convert the return value to aproper response object, call :func: make_response .
① req = _request_ctx_stack.top.request 將請求上下文棧頂?shù)恼埱筚x值給req枫夺,(req 會包含請求的詳細信息)
②rule = req.url_rule 將req 中的url_rule (’/’)賦值給rule,(請求和flaskapp中代碼一致)
③ 在運行@app.route("/") 時將endpoint( ‘/’)和view_func(’index’)的映射關(guān)系到了view_functions字典中绘闷。
④如果在flaskapp 代碼中找不到輸入的 URL橡庞,會返回 404 錯誤。
⑤如果輸入的URL在flaskapp 代碼有相應(yīng)的 URL印蔗,會返回 flaskapp 對應(yīng)的視圖函數(shù)扒最。
⑥上面說的是完整的URL-Viewfunc映射關(guān)系,flaskapp 以及 WSGI server 中使用的是endpoint(‘/’, ‘/index’, ‘/about’) -Viewfunc 的映射關(guān)系华嘹。
⑦總結(jié)來說吧趣,dispatch_request()判斷用戶輸入的URL在flask應(yīng)用中有沒有相關(guān)的定義。如果有耙厚,將對應(yīng)的視圖函數(shù)的內(nèi)容返回到full_dispatch_request: rv = self.preprocess_request()强挫。
(6) full_dispatch_request最后會調(diào)用finalize_request(rv) 方法將返回結(jié)果轉(zhuǎn)換成一個真正的響應(yīng)。
(7) finalize_request(rv) 代碼不復雜薛躬,主要就是使用response = self.make_response(rv) 將處理結(jié)果變成一個真正的響應(yīng)(視圖函數(shù)中字符串變成html形式)俯渤,最后return response,這個響應(yīng)會返回到full_dispatch_request型宝,然后返回到wsgi_app八匠。
(8) 以上wsgi_app 完成了一個請求處理的過程,最后return response(environ, start_response) 將處理結(jié)果返回給 WSGI server趴酣,WSGI server再返回給客戶端(瀏覽器)梨树,瀏覽器中顯示了2017-08-21,即flaskapp中index視圖函數(shù)的返回值岖寞。
作者:sinat_36651044
來源:CSDN
原文:https://blog.csdn.net/sinat_36651044/article/details/77532510
版權(quán)聲明:本文為博主原創(chuàng)文章抡四,轉(zhuǎn)載請附上博文鏈接!