<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文主要梳理了flask
原始碼中route
的設計思路。
首先,從WSGI
協定的角度介紹flask route
的作用;
其次,詳細講解如何藉助werkzeug
庫的Map
、Rule
實現route
;
最後,梳理了一次完整的http請求中route
的完整流程。
本文參考的是flask 0.5
版本的程式碼。
flask 0.1
版本的程式碼非常短,只有600多行,但是這個版本缺少blueprint
機制。
因此,我參考的是0.5版本。
直接使用flask
官方檔案中的例子
from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World!' @app.route('/post/') def show_post(post_id): # show the post with the given id, the id is an integer return 'Post %d' % post_id if __name__ == '__main__': app.run()
此例中,使用app.route
裝飾器,完成了以下兩個url
與處理常式的route
:
{ '/': hello_world, '/post/' : show_post }
這樣做的效果為:
當http請求的url為'/'時,flask會呼叫hello_world函數;
當http請求的url為'/post/<某整數值>'(例如/post/32)時,flask會呼叫show_post函數;
從上面的範例中其實可以明白:flask route的作用就是建立url與處理常式的對映。
WSGI協定將處理請求的元件按照功能及呼叫關係分成了三種:server, middleware, application。
其中,server可以呼叫middleware和application,middleware可以呼叫application。
符合WSGI的框架對於一次http請求的完整處理過程為:
server讀取解析請求,生成environ和start_response,然後呼叫middleware;
middleware完成自己的處理部分後,可以繼續呼叫下一個middleware或application,形成一個完整的請求鏈;
application位於請求鏈的最後一級,其作用就是生成最終的響應。
http伺服器(比如,nginx)--> WSGI server(比如gunicorn,SimpleHttpServer)-->middleware--> middleware--> ... -->application
如果接觸過Java Web 開發的人可能會立刻發現,這與servlet中的middleware機制是完全一致的。
特別重要的:
在上一小節的範例中app = Flask(__name__)
建立了一個middleware,
而這個middleware的核心作用是進行請求轉發(request dispatch)。
上面這句話非常重要,請在心裡重複一百遍。
上面這句話非常重要,請在心裡重複一百遍。
上面這句話非常重要,請在心裡重複一百遍。
進行請求轉發的前提就是能夠建立url與處理常式之間的對映關係,即route
功能。
因此,在flask
中,route是Flask類的一個裝飾器。
通過上一小節,我們知道以下兩點:
flask route
是url與處理常式的對映關係;Flask
這個middleware
負責完成對url對應的處理常式的呼叫;那麼,如果是我們自己來實現route
,思路也很簡單:
Flask
,這個類是一個middleware,並且有一個字典型的成員變數url_map
;url_map = {url : function}
function
,然後呼叫function;flask的實現思路也是這樣的。
class Flask(object): def __init__(self): self.url_map = {} # 此處定義儲存url與處理常式的對映關係 def __call__(self, environ, start_response): # 根據WSGI協定,middleware必須是可呼叫物件 self.dispatch_request() # Flask的核心功能 request dispatch return application(environ, start_response) #最後呼叫下一級的application def route(self, rule): # Flask使用裝飾器來完成url與處理常式的對映關係建立 def decorator(f): # 簡單,侵入小,優雅 self.url_map[rule] = f return f return decorator def dispath_request(self): url = get_url_from_environ() #解析environ獲得url return self.url_map[url]() #從url_map中找到對應的處理常式,並呼叫
至此, 一個簡單的Flask
middleware的骨架就完成了。
上面的Flask
類主要功能包括:
當然,在實際中,不可能這麼簡單,但是基本思路是一致的。
需要指出,上面實現的最簡單的Flask
類還是有很多問題的。
比如,HTTP請求中相同的url,不同的請求方法,比如GET,POST如果對應不同的處理常式,該如何處理?
flask使用了werkzeug
庫中的Map
和Rule
來管理url與處理常式對映關係。
首先需要簡單瞭解一下Map
和Rule
的作用:
在werkzeug
中,Rule
的主要作用是儲存了一組url
,endpoint
,methods
關係:
每個(url, endpoint, methods)都有一個對應的Rule物件:
其實現如下:
class Rule(object): def __init__(self, url, endpoint, methods): self.rule = url self.endpoint = endpoint self.methods = methods
這裡需要解釋一下endpoint
:
前面說過:url與其處理常式可以使用一個字典來實現:{url: function}
flask
在實現的時候,在中間加了一箇中介endpoint
,於是,url與處理常式的對映變成了這樣:
url-->endpoint-->function #一個url對應一個endpoint,一個endpoint對應一個function {url: endpoint} # 儲存url與endpoint之間的關係 {endpoint: function} #儲存endpoint與function之間的關係
於是,剛才我們實現的簡單的flask
骨架中{url: function}
的字典,就變成了{endpoint: function}
,而{url: endpoint}
這個對映關係就需要藉助Map
和Rule
這兩個類來完成。
可以發現:endpoint
就是url和處理常式對映關係中的一箇中介,所以,它可以是任何可以用作字典鍵的值,比如字串。
但是在實際使用中endpoint
,一般endpoint
均為字串,並且預設情況下:
Flask.route
裝飾器建立的對映關係,那麼endpoint
就是處理常式的函數名;blueprint
建立的對映關係,那麼endpoint
是blueprint名.處理常式名;因為,每建立一個url-->endpoint-->function
關係就會建立一個Rule
物件,所以,會有很多Rule
物件存在。
Map
的作用則是儲存所有Rule
物件。
所以,一般情況下Map
的用法如下:
m = Map([ Rule('/', endpoint='index'), Rule('/downloads/', endpoint='downloads/index'), Rule('/downloads/', endpoint='downloads/show') ])
在flask的原始碼中
class Flask(object): def __init__(self): self.url_map = Map() # url_map為儲存所有Rule關係的容器Map self.view_functions = {} # view_functions儲存endpoint-->function
url_map
儲存所有的(url, endpoint, method)
關係view_functions
儲存所有的{endpoint, function}關係所以,對於一個url,只要能找到(url,endpoint,method)
,就能根據endpoint
找到對應的function
。
首先,建立Flask
物件:
app = Flask(__name__)
然後,建立url
與function
之間的對映關係:
@app.route('/') def hello_world(): return 'Hello World!'
在裝飾器route
中,建立(url, endpoint, method)
和{endpoint: function}
兩組對映關係:
if endpoint is None: endpoint = view_func.__name__ # 預設使用響應函數名作為endpoint self.url_map.add(Rule(url, endpoint, method)) # 儲存(url, endpoint, method)對映關係 self.view_functions[endpoint] = view_func # 儲存{endpoint: function}對映關係
這樣,就完成了對url和響應函數的對映關係。
下一步,呼叫WSGI server響應http請求,在文章開始的範例中使用:
app.run()
呼叫python
標準庫提供的WSGI server,在實際使用時,可能是gunicorn
或uwsgi
。
不論server是什麼,最終都會呼叫Flask.__call__
函數。這個函數完成request dispatch的任務。
對於request dispatch而言,首先根據請求,解析environ,得到url,然後呼叫Map.match
函數,這個函數會最終找到預先儲存的(url, endpoint, method)
對映,然後返回(endpoint, url請求引數),由於得到了endpoint,然後,可以從Flask.view_functions
中直接取到對應的響應函數,所以,可以直接進行函數呼叫
self.view_functions[endpoint](url請求引數)
至此,就完成了完整的route
。
flask
的Flask
類是WSGI
的dispatch middleware
;
Flask
的url_map
儲存所有的(url, endpoint, method)對映關係;
Flask
的view_functions
儲存所有的{endpoint: function}對映關係;
dispath request
就是根據url找到endpoint,再根據endpoint找到function,最後呼叫function的過程
以上就是flask route對協定作用及設計思路的詳細內容,更多關於flask route協定設計的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45