小編寫這篇文章的一個主要目的,主要是給大家講解一下flask route,講解的內容是flask route協議的一些相關作用,還有具體的一些設計思路,具體的思路性問題,下面去給大家做一個詳細解答。
引言
本文主要梳理了flask源碼中route的設計思路。
首先,從WSGI協議的角度介紹flask route的作用;
其次,詳細講解如何借助werkzeug庫的Map、Rule實現route;
最后,梳理了一次完整的http請求中route的完整流程。
flask route設計思路
源碼版本說明
本文參考的是flask 0.5版本的代碼。
flask 0.1版本的代碼非常短,只有600多行,但是這個版本缺少blueprint機制。
因此,我參考的是0.5版本。
flask route示例
直接使用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的作用
從上面的示例中其實可以明白: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的實現思路
通過上一小節,我們知道以下兩點:
flask route是url與處理函數的映射關系;
在http請求時,Flask這個middleware負責完成對url對應的處理函數的調用;
那么,如果是我們自己來實現route,思路也很簡單:
建立一個類Flask,這個類是一個middleware,并且有一個字典型的成員變量url_map;
url_map={url:function}
當http請求時,進行request dispatch:根據url,從url_map中找到function,然后調用function;
調用后續的middleware或application,并把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中找到對應的處理函數,并調用
至此,一個簡單的Flaskmiddleware的骨架就完成了。
上面的Flask類主要功能包括:
符合WSGI協議的middleware:可被調用,并且可以調用application
能夠保存url與處理函數的映射信息
能夠根據url找到處理函數并調用(即,request dispatch)
當然,在實際中,不可能這么簡單,但是基本思路是一致的。
werkzeug庫中的Map與Rule在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。
route的完整流程
首先,建立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的過程
綜上所述,這篇文章就給大家介紹到這里了,希望可以給大家帶來幫助。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/128315.html
摘要:引言本文主要梳理了源碼中的設計思路。協議將處理請求的組件按照功能及調用關系分成了三種。不論是什么,最終都會調用函數。 引言 本文主要梳理了flask源碼中route的設計思路。首先,從WSGI協議的角度介紹flask route的作用;其次,詳細講解如何借助werkzeug庫的Map、Rule實現route;最后,梳理了一次完整的http請求中route的完整流程。 flask rou...
小編寫這篇文章的主要目的,主要是來給大家做出一個比較詳細解答,主要是給大家解答關于python中的一些知識,比如Flask實現接手與上傳圖片,下面就給大家詳細解答下。 接下來給搭建講解Flask如何接受圖片文件,上面是復雜寫法,下面是簡單寫法,二選一即可。 思路整理:接收圖片->定義一個圖片存放的位置->給圖片重命名(為了唯一性)->保存操作-&...
摘要:服務器通過協議與客戶端通信,因此也被稱為服務器。本文標題為從零開始搭建論壇一服務器與框架本文鏈接為更多閱讀自己動手開發網絡服務器一自己動手開發網絡服務器二自己動手開發網絡服務器三服務器網關接口實現原理分析最佳實踐指南應用淺談框架編程簡介 之前用 Django 做過一個小的站點,感覺Django太過笨重,于是就準備換一個比較輕量級的 Web 框架來玩玩。Web.py 作者已經掛掉,項目好...
摘要:本篇對應書本第二章程序的基本結構。初始化導入模塊創建類的實例注對于開發者來說,傳給應用程序構造函數的參數是比較容易弄混淆的。不同的請求方法發送到相同的上時,會使用不同的視圖函數進行處理。 本系列筆記是我閱讀Miguel Grinberg的《Flask Web Development》的筆記,標題與書本同步。希望通過記錄技術筆記的方式促進自己對知識的理解。 本篇對應書本第二章:程序的基本...
閱讀 911·2023-01-14 11:38
閱讀 878·2023-01-14 11:04
閱讀 740·2023-01-14 10:48
閱讀 1983·2023-01-14 10:34
閱讀 942·2023-01-14 10:24
閱讀 819·2023-01-14 10:18
閱讀 499·2023-01-14 10:09
閱讀 572·2023-01-14 10:02