亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

flask源碼走讀

Coly / 1427人閱讀

摘要:另外,如果你對(duì)模板渲染部分的內(nèi)容感興趣,也可以考慮閱讀文檔文檔文檔源碼閱讀,可以參考下面的函數(shù)打斷點(diǎn),再測(cè)試一個(gè)請(qǐng)求,理清過(guò)程。

Flask-Origin 源碼版本

一直想好好理一下flask的實(shí)現(xiàn),這個(gè)項(xiàng)目有Flask 0.1版本源碼并加了注解,挺清晰明了的,我在其基礎(chǔ)上完成了對(duì)Werkzeug的理解部分,大家如果想深入學(xué)習(xí)的話,可以參考werkzeug_flow.md.

閱讀前

為了更容易理解Flask的實(shí)現(xiàn)原理,你需要對(duì)WSGI協(xié)議以及HTTP協(xié)議有一些了解,建議先簡(jiǎn)單瀏覽下面的基本知識(shí):

PEP 0333和PEP 3333(WSGI實(shí)現(xiàn))

HTTP概述

Flask內(nèi)部實(shí)現(xiàn)大量依賴于Werkzeug,包括請(qǐng)求和響應(yīng)對(duì)象,路由匹配,URL生成等等,你可以閱讀Werkzeug的文檔來(lái)深入了解這些內(nèi)容的具體實(shí)現(xiàn)。另外,如果你對(duì)模板渲染部分的內(nèi)容感興趣,也可以考慮閱讀Jinja2文檔:

Werkzeug文檔

Jinja2文檔

werkzeug源碼閱讀,可以參考下面的函數(shù)打斷點(diǎn),再測(cè)試一個(gè)請(qǐng)求,理清過(guò)程。
其實(shí)可以參考簡(jiǎn)化后web服務(wù)實(shí)現(xiàn)思路,socket建立后,監(jiān)聽recv到的請(qǐng)求信息(no_wsgi_dome.no_wsgi.Socket._handle)并解析,然后調(diào)用相應(yīng)的app.route對(duì)應(yīng)的view_func.整個(gè)過(guò)程可以大致分為兩部分:
1. app-> werkzeug-> http-> socket 啟動(dòng)端口監(jiān)聽,注冊(cè)各種方法.
2. socket recv到請(qǐng)求-> 初始化RequestHandlerClass-> 調(diào)用Flask.__call__, wsgi_app在請(qǐng)求上下文中執(zhí)行預(yù)處理方法,視圖方法,后響應(yīng)方法等.
flask啟動(dòng)流程,只追溯了app到http再到socket的啟動(dòng),主流程就是BaseWSGIServer初始化調(diào)用了HTTPServer的初始化,進(jìn)而初始化了BaseServer,在socketserver上啟動(dòng)了服務(wù)開始監(jiān)聽端口:
flask.Flask.run -> werkzeug.serving.run_simple ->
werkzeug.serving.run_simple.inner ->werkzeug.serving.make_server ->
BaseWSGIServer->HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler) ->
BaseServer.__init__(self, server_address, RequestHandlerClass) ->
werkzeug.serving.run_simple.inner.srv.serve_forever() ->
socketserver.BaseServer.serve_forever 建立socket服務(wù)開始監(jiān)聽,當(dāng)ready也就是有recv到請(qǐng)求時(shí)開始 _handle_request_noblock
flask處理請(qǐng)求流程,追溯了socket接受到請(qǐng)求后觸發(fā)app處理請(qǐng)求的主流程:
curl發(fā)出請(qǐng)求 ->
socket接受到請(qǐng)求 ->
SocketServer.BaseServer.serve_forever._handle_request_noblock ->
SocketServer.BaseServer.process_request ->
SocketServer.BaseServer.finish_request ->
socketserver.BaseServer.__init__:self.RequestHandlerClass(request, client_address, self)  ->
這里要找出RequestHandlerClass是如何初始化的,它的真身是什么 ->
socketserver.TCPServer.__init__:BaseServer.__init__(self, server_address, RequestHandlerClass) ->
http.server.HTTPServer(未重寫__init__) ->
werkzeug.serving.BaseWSGIServer:HTTPServer.__init__(self, get_sockaddr(host, int(port),self.address_family), handler) (此處handler就是WSGIRequestHandler) ->
RequestHandlerClass的真身已經(jīng)找到,就是WSGIRequestHandler 也就是說(shuō)每次請(qǐng)求來(lái)了都初始化一個(gè)WSGIRequestHandler去處理 ->
處理的入口應(yīng)該是werkzeug.serving.WSGIRequestHandler.handle可是簡(jiǎn)單一看并沒找到是如何開始處理請(qǐng)求的->
往它的父類BaseHTTPRequestHandler中找也沒有 ->
再往上socketserver.StreamRequestHandler ->
找到了SocketServer.BaseRequestHandler.__init__:try:self.handle() 關(guān)鍵點(diǎn) ->
開始調(diào)用子類WSGIRequestHandler中的handle方法 ->
werkzeug.serving.WSGIRequestHandler (注意handler和handle_one_request,WSGIRequestHandler重載了BaseHTTPServer.BaseHTTPRequestHandler中的方法,BaseHTTPRequestHandler由重載了 SocketServer.BaseRequestHandler )->
werkzeug.serving.WSGIRequestHandler.handle_one_request調(diào)用werkzeug.serving.WSGIRequestHandler.run_wsgi 開始處理請(qǐng)求 ->
run_wsgi.execute(self.server.app)將請(qǐng)求交予app來(lái)處理 ->
flask.Flask.__call__ -> 
flask.Flask.wsgi_app 開始app內(nèi)的流程,交由wsgi_app在請(qǐng)求上下文中執(zhí)行預(yù)處理方法,視圖方法,后響應(yīng)方法等。


可以看到實(shí)現(xiàn)過(guò)程中Server,Handler用到了繼承并重載,層層包裝了web服務(wù)
BaseWSGIServer繼承了HTTPServer重寫了BaseServer.serve_forever(包了一層),
HTTPServer繼承了TCPServer重寫了server_bind,
TCPServer繼承了BaseServer重寫了server_bind,
主要思路要理清socket接受接請(qǐng)求后如何用請(qǐng)求觸發(fā)調(diào)用app,這里主要是SocketServer.BaseRequestHandler.__init__:try:self.handle() 這個(gè)__init__才是處理請(qǐng)求真正開始的地方.
進(jìn)一步

web的最原始的實(shí)現(xiàn)見 no_wsgi_dome ,不使用werkzeug,不使用wsgi約束,只是用socket如何實(shí)現(xiàn)http服務(wù).這個(gè)對(duì)理解wsgi對(duì)http以及socket的封裝有很好的借鑒意義.

補(bǔ)充了本地上下文相關(guān)的本地線程、本地堆棧、本地代理,并寫了個(gè)LocalProxy_dome.py 輔助理解flask中是如何使用LocalProxy的。

我通過(guò)打斷點(diǎn),理通了app的啟動(dòng)和接受請(qǐng)求到處理請(qǐng)求的過(guò)程,可以參考werkzeug_flow.md配合flask_dome.py并手動(dòng)打斷點(diǎn)嘗試一下.

根據(jù)下面的提示,自己理一下吧.

Flask中的請(qǐng)求響應(yīng)循環(huán)

路由系統(tǒng)

本地上下文

請(qǐng)求與響應(yīng)對(duì)象

session

藍(lán)本

模板渲染

最后,要是覺得不錯(cuò)的話,點(diǎn)個(gè)贊支持一下吧,相關(guān)源碼都放到了 我的github.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/43535.html

相關(guān)文章

  • 記一次 Mybatis 一級(jí)緩存清理無(wú)效引起的源碼走讀

    摘要:今天對(duì)象在學(xué)習(xí)時(shí)發(fā)現(xiàn)對(duì)象的方法并不能清理一級(jí)緩存同一下相同查詢條件返回的結(jié)果還是舊值。測(cè)試代碼如下上網(wǎng)搜索網(wǎng)上搜索找到了相同問(wèn)題并沒有人解答。例如查看官方文檔實(shí)例有一個(gè)本地緩存在執(zhí)行和時(shí)被清理。要明確地關(guān)閉它獲取打算做更多的工作你可以調(diào)用。 今天對(duì)象在學(xué)習(xí) Mybatis 時(shí)發(fā)現(xiàn) org.apache.ibatis.session.SqlSession 對(duì)象的 clearCache()...

    voyagelab 評(píng)論0 收藏0
  • Docker 源碼走讀 - 在運(yùn)行 Docker run 時(shí)發(fā)生了什么?

    摘要:源碼走讀在運(yùn)行時(shí)發(fā)生了什么標(biāo)簽空格分隔原文作者是,原文地址是在這篇博文中我將回答一下問(wèn)題運(yùn)行一個(gè)期間內(nèi)部發(fā)生了什么開始首先從并檢查代碼。這個(gè)發(fā)生在和行之間。如果一個(gè)錯(cuò)誤發(fā)生,它會(huì)被記錄,然后程序退出。這些覆蓋了在客戶端里面發(fā)生了什么。 Docker 源碼走讀 - 在運(yùn)行 Docker run 時(shí)發(fā)生了什么? 標(biāo)簽(空格分隔): Docker 原文作者是 Frank Scho...

    趙連江 評(píng)論0 收藏0
  • SpringMVC HandlerInterceptor詭異問(wèn)題排查

    摘要:攔截器注冊(cè)配置攔截器注冊(cè)配置通過(guò)可以發(fā)現(xiàn)中的的清理工作沒有得到執(zhí)行。只會(huì)在出現(xiàn)異常,返回或正常執(zhí)行結(jié)束才會(huì)從索引依次往前執(zhí)行。 發(fā)現(xiàn)問(wèn)題 最近在進(jìn)行壓測(cè)發(fā)現(xiàn),有一些接口時(shí)好時(shí)壞,通過(guò)sentry日志平臺(tái)及sky walking平臺(tái)跟蹤發(fā)現(xiàn),用戶張三獲取到的用戶上下文確是李四。 代碼走讀 用戶登錄下上文 /** * 用戶登錄下上文 * * @author : jamesfu * @da...

    Baaaan 評(píng)論0 收藏0
  • EventBus框架庫(kù)代碼走讀,帶你全面理解View的繪制流程

    摘要:如果當(dāng)前不是主線程則直接調(diào)用,如果是線程則創(chuàng)建一個(gè)加入到后臺(tái)的一個(gè)隊(duì)列,最終由中的一個(gè)線程池去調(diào)用。拋出線程狀態(tài)非法異常。 while (clazz != null) {String name = clazz.getName();if (name.startsWith(java.) || name.starts...

    番茄西紅柿 評(píng)論0 收藏2637

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<