flask源碼走讀

Flask-Origin

源碼版本

一直想好好理一下flask的實現,這個項目有Flask 0.1版本源碼並加了註解,挺清晰明瞭的,我在其基礎上完成了對Werkzeug的理解部分,大家如果想深入學習的話,可以參考werkzeug_flow.md.

閱讀前

爲了更容易理解Flask的實現原理,你需要對WSGI協議以及HTTP協議有一些瞭解,建議先簡單瀏覽下面的基本知識:

Flask內部實現大量依賴於Werkzeug,包括請求和響應對象,路由匹配,URL生成等等,你可以閱讀Werkzeug的文檔來深入瞭解這些內容的具體實現。另外,如果你對模板渲染部分的內容感興趣,也可以考慮閱讀Jinja2文檔:

werkzeug源碼閱讀,可以參考下面的函數打斷點,再測試一個請求,理清過程。

其實可以參考簡化後web服務實現思路,socket建立後,監聽recv到的請求信息(no_wsgi_dome.no_wsgi.Socket._handle)並解析,然後調用相應的app.route對應的view_func.整個過程可以大致分爲兩部分:
1. app-> werkzeug-> http-> socket 啓動端口監聽,註冊各種方法.
2. socket recv到請求-> 初始化RequestHandlerClass-> 調用Flask.__call__, wsgi_app在請求上下文中執行預處理方法,視圖方法,後響應方法等.

flask啓動流程,只追溯了app到http再到socket的啓動,主流程就是BaseWSGIServer初始化調用了HTTPServer的初始化,進而初始化了BaseServer,在socketserver上啓動了服務開始監聽端口:

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服務開始監聽,當ready也就是有recv到請求時開始 _handle_request_noblock

flask處理請求流程,追溯了socket接受到請求後觸發app處理請求的主流程:

curl發出請求->socket接受到請求 ->
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的真身已經找到,就是WSGIRequestHandler 也就是說每次請求來了都初始化一個WSGIRequestHandler去處理 ->
處理的入口應該是werkzeug.serving.WSGIRequestHandler.handle可是簡單一看並沒找到是如何開始處理請求的->
往它的父類BaseHTTPRequestHandler中找也沒有 ->
再往上socketserver.StreamRequestHandler ->
找到了SocketServer.BaseRequestHandler.__init__:try:self.handle() 關鍵點 ->
開始調用子類WSGIRequestHandler中的handle方法 ->
werkzeug.serving.WSGIRequestHandler (注意handler和handle_one_request,WSGIRequestHandler重載了BaseHTTPServer.BaseHTTPRequestHandler中的方法,BaseHTTPRequestHandler由重載了 SocketServer.BaseRequestHandler )->
werkzeug.serving.WSGIRequestHandler.handle_one_request調用werkzeug.serving.WSGIRequestHandler.run_wsgi 開始處理請求 ->
run_wsgi.execute(self.server.app)將請求交予app來處理 ->
flask.Flask.__call__ -> 
flask.Flask.wsgi_app 開始app內的流程,交由wsgi_app在請求上下文中執行預處理方法,視圖方法,後響應方法等。

可以看到實現過程中Server,Handler用到了繼承並重載,層層包裝了web服務

BaseWSGIServer繼承了HTTPServer重寫了BaseServer.serve_forever(包了一層),
HTTPServer繼承了TCPServer重寫了server_bind,
TCPServer繼承了BaseServer重寫了server_bind,
主要思路要理清socket接受接請求後如何用請求觸發調用app,這裏主要是SocketServer.BaseRequestHandler.__init__:try:self.handle() 這個__init__纔是處理請求真正開始的地方.

進一步

  1. web的最原始的實現見 no_wsgi_dome ,不使用werkzeug,不使用wsgi約束,只是用socket如何實現http服務.這個對理解wsgi對http以及socket的封裝有很好的借鑑意義.
  2. 補充了本地上下文相關的本地線程、本地堆棧、本地代理,並寫了個LocalProxy_dome.py 輔助理解flask中是如何使用LocalProxy的。
  3. 我通過打斷點,理通了app的啓動和接受請求到處理請求的過程,可以參考werkzeug_flow.md配合flask_dome.py並手動打斷點嘗試一下.
  4. 根據下面的提示,自己理一下吧.
    • Flask中的請求響應循環
    • 路由系統
    • 本地上下文
    • 請求與響應對象
    • session
    • 藍本
    • 模板渲染

最後,要是覺得不錯的話,點個贊支持一下吧,相關源碼都放到了 我的github.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章