所謂分組就是按照前綴分佈映射python
如:app
/product/(\w+)/(?P<id>\d+ # 匹配/product/123123 的前綴
好比什麼類別,類別下的什麼產品 等,
ide
用request path進行正則匹配,因此須要用到正則分組post
分析咱們當前代碼,只有__call__方法纔是真正在作處理,也就是說得在這個方法獲取分組url
經過動態屬性spa
經過動態屬性,將匹配到的命名分組域當前request對象,由於一個請求對應不一樣的request實例code
這裏是一個實例只能對應一個requestorm
@dec.wsgify def __call__(self, request:Request): for methods, pattern, handler in self.ROUTE: print(self.ROUTE) if not methods or request.method in methods: if request.method.upper() in methods: matcher = pattern.match(request.path) if matcher: request.args = matcher.group() #全部的分組 request.kwargs = matcher.groupdict() #全部的命名分組 return handler(request) raise exc.HTTPNotFound('no')
對咱們而言命名後的分組纔有價值,動態增長屬性以後,增長了屬性,爲了獲取分組信息
router
打印這兩個以下:server
>>>>>> / >>>>>> {
每個前綴所對應的字段咱們認爲是不一樣的路由實例,每一個實例保存本身的前綴,在內部實現Application,這一就將Application變爲多個實例
思路:經過request的前綴名來判斷不一樣的業務,經過不一樣的前綴名來調用不一樣的方法
比上一節多了一級
需求:
URL 爲/product/12345,那麼須要將產品id 12345取出,用分組包裝,一旦分離出來前綴product,那麼這就是一個一級路由分組,經過第一級判斷交給誰來作
再經過Applicaction 判斷前綴扔給不一樣的對象,而對象內又對應不一樣的pattern(正則)再交給不一樣的handler
例:
p = Router('/product') 直接轉化前綴
p.get(pattern正則) 匹配路徑,replice以後換爲空,切分後再判斷
提交的模式
/product/(\w+)/(?P<id>\d+)
能夠理解爲每個前綴都是一個不一樣的路由實例,每一個實例保留的是業務分組
前綴必須以/根開始
前綴不能在後面加/ ,用戶不認這個,只能strip掉
創建隸屬關係
一個prefix下有若干個url,創建了某種關係,好比/xxx/xx 這裏URL屬於xxx的管理範圍;只要符合格式就屬於prefix的管轄範圍
一個Router類 經過每個類都管理一個prefix
以前全部方法都是在Application類方法中,如今要將其拆開
如今路由表方式應該如何處理?
不一樣前綴對應不一樣的router實例,那麼這些方法就不是類方法了,而是對應一個實例方法
咱們如今想讓每一個業務分開,各管各的,獨立負責本身的路由信息對應不一樣的實例;
若是是一個實例的話那麼能夠獨立管理,那麼若是是類屬性則不適用,由於類屬性是共享的,因此要由實例本身管理獨立的路由表
定義Application類,只保存全部註冊的路由對象,__call__依然是回調的入口,一切從這裏開始
在這裏須要遍歷全部的Rtouer實例,這裏是Router實例不是類屬性
找到實例以後返回response便可
路由分組
按照前綴分別映射
分析:
application是做爲入口的東西是單一的,因此須要固定
大多數server 須要傳遞一個單一的對象,會找到入口wsgi的入口,也就是__call__
首先知道每個前綴的管理是不一樣的對象,這個類爲Router
將註冊的方法移到Router類,實現一個實例管理當前業務的url,實際上仍是meatch方法
原則:只找一個route
代碼以下:
解決前綴問題
# /product/tv/1234 /product/tv/abc # /python/student/16 # /product/(\w+)/(?<id>\d+)
找到定義初始化,一個實例獨立管理,路由要在初始化的時候定義好
prefix 是前綴,默認爲空;
每一個實例自行管理本身的路由表;
class Router: def __init__(self,prefix:str=''): self.__prefix = prefix self.__routetable = []
定義route
@property def prefix(self): return self.__routetable def route(self, pattern, *methods): # 傳入正則和路徑 def wapper(handler): uri = (methods,re.compile(pattern),handler) self.__routetable.append(uri) return handler return wapper
定義請求方法
@property def prefix(self): return self.__prefix def get(self,pattern): return self.route('GET', pattern) def post(self,pattern): return self.route('POST', pattern)
定義maetch **
·判斷是否屬於本身實例管理的prefix
·若是不是以它爲前綴的直接return None
·若是歸屬本身管理全部循環做完沒有匹配到直接默認return None 或者404
·並修改前綴 經過replace,由於傳遞url是帶的,可是在處理的時候是
def match(self,request:Request): # 若是不是以某爲前綴則直接return空,那麼則沒有註冊,當__call__掃描的時候沒有獲取到則直接404 if not request.path.startswith(self.prefix): return for methods, pattern, handler in self.__routetable: if not methods or request.method.upper() in methods: # 咱們寫的pattern是/produ ct/(\w+)/(?<id>\d+),匹配的是後半部分,那匹配也是後半部分,因此要去掉前綴 matcher = pattern.match(request.path.replace(self.prefix)) if matcher: request.kwargs = matcher.groupdict() return handler
定義Application
定義Application
·定義ROUTERS列表用於管理實例對象
·若是是外界能夠註冊進來,那確定不是實例,因此還須要類方法
註冊的方式:
p = Router('/product') 直接轉化前綴
p.get(pattern正則) 匹配路徑,replice以後換爲空,切分後再判斷
沒有必要實例化,註冊的東西都須要在這之上
class Application: ROUTERS = [] #將Router註冊進來 @classmethod def register(cls,router:Router): cls.ROUTERS.append(router)
定義__call__方法
查找每一個ROUTERS 返回response,前提是找到request以後
若是能處理則必須返回數據,判斷是否有數據要麼None要麼非None
@dec.wsgify def __call__(self, request:Request): # 獲取response,問每個router進行詢問,調用實例化的router進行match方法,將request傳遞過去 for router in self.ROUTERS: response = router.match(request) # 一旦有數據獲取那麼直接返回response,若是所有執行完沒有路由,則直接404 if response: return response raise exc.HTTPNotFound('no')
若是沒有思路的話先定義application最後再定義match方法
註冊
idx = Router() py = Router('/py')
這樣一寫,確定是由註冊方法進行註冊,因此還須要調用註冊方法
Application.register(idx) Application.register(py)
只要application可以調用,那麼就直接到__call__中遍歷
這樣經過業務的分級進行分別管理
完整以下:
class Router: def __init__(self,prefix:str=''): # /product/tv/1234 /product/tv/abc # /python/student/16 # /produ ct/(\w+)/(?<id>\d+) self.__prefix = prefix self.__routetable = [] def route(self,pattern,*methods): def wapper(handler): uri = (methods,re.compile(pattern),handler) print('uri:',uri) self.__routetable.append(uri) return handler return wapper def get(self,pattern): return self.route(pattern,'GET') def post(self,pattern): return self.route(pattern,'POST') def match(self,request:Request): if not request.path.startswith(self.__prefix): return None for methods,pattern,handler in self.__routetable: if not methods or request.method.upper() in methods: matcher = pattern.match(request.path.replace(self.__prefix,'',1)) if matcher: request.kwargs = matcher.groupdict() return handler(request) class App: ROUTERS = [] @classmethod def register(cls,router:Router): cls.ROUTERS.append(router) @dec.wsgify def __call__(self, request:Request): for router in self.ROUTERS: response = router.match(request) return response raise exc.HTTPNotFound('no') idx = Router() App.register(idx) @idx.get('^/$') def index(request:Request): res = Response() res.body = 'aa'.encode() return res if __name__ == "__main__": ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) server.serve_forever() server.server_close()