类Flask框架实现
路由route
路由功能实现
路由类实现
#路由 # url = 'http://127.0.0.1:9999/python/index.html?id=5&name=wayne&age=20' # path = '/python/index.html' class Router: ROUTETABLE = {} def register(self,path,handler): self.ROUTETABLE[path] = handler def indexhandler(request): return '<h1>欢迎来到index.html</h1>' def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" router = Router() router.register('/',indexhandler) router.register('/python',pythonhandler)
404处理
注册函数的改造
将注册函数改造成装饰器
class Router: ROUTETABLE = {} @classmethod #注册路由,装饰器 def register(cls,path): def wrapper(handler): cls.ROUTETABLE[path] = handler return handler return wrapper @Router.register('/') #indexhandler = Router.register('/')(indexhandler) def indexhandler(request): return '<h1>欢迎来到index.html</h1>' @Router.register('/python') def pythonhandler(request): return "<h1>欢迎来到python.html</h1>"
将路由功能合并到App类中
from webob import Request,Response from webob.dec import wsgify from wsgiref.simple_server import make_server from webob.exc import HTTPNotFound class Router: ROUTETABLE = {} @classmethod #注册路由,装饰器 def register(cls,path): def wrapper(handler): cls.ROUTETABLE[path] = handler return handler return wrapper @Router.register('/') #indexhandler = Router.register('/')(indexhandler) def indexhandler(request): return '<h1>欢迎来到index.html</h1>' @Router.register('/python') def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" class App: _Router = Router @wsgify def __call__(self, request:Request): try: return self._Router.ROUTETABLE[request.path](request) except: raise HTTPNotFound('<h1>你访问的网页被外星人劫持了</h1>') if __name__ == '__main__': ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) try: server.serve_forever() except KeyboardInterrupt: server.shutdown() server.server_close()
路由正则匹配
from webob import Request,Response from webob.dec import wsgify from wsgiref.simple_server import make_server from webob.exc import HTTPNotFound import re class Router: ROUTETABLE = [] @classmethod #注册路由,装饰器 def register(cls,pattern): def wrapper(handler): cls.ROUTETABLE.append((re.compile(pattern),handler)) return handler return wrapper @Router.register('^/$') #indexhandler = Router.register('/')(indexhandler) def indexhandler(request): return '<h1>欢迎来到index.html</h1>' @Router.register('^/python$') def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" class App: _Router = Router @wsgify def __call__(self, request:Request): for pattern,handler in self._Router.ROUTETABLE: if pattern.match(request.path): #正则匹配 return handler(request) raise HTTPNotFound('<h1>你访问的网页被外星人劫持了</h1>') if __name__ == '__main__': ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) try: server.serve_forever() except KeyboardInterrupt: server.shutdown() server.server_close()
正则表达式分组捕获
from webob import Request,Response from webob.dec import wsgify from wsgiref.simple_server import make_server from webob.exc import HTTPNotFound import re class Router: ROUTETABLE = [] @classmethod #注册路由,装饰器 def register(cls,pattern): def wrapper(handler): cls.ROUTETABLE.append((re.compile(pattern),handler)) return handler return wrapper @Router.register(r'^/$') @Router.register(r'^/(?P<id>d+)$') def indexhandler(request): return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.get('id')) @Router.register('^/python$') def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" class App: _Router = Router @wsgify def __call__(self, request:Request): for pattern,handler in self._Router.ROUTETABLE: matcher = pattern.match(request.path) #正则匹配 if matcher: #动态为request增加属性 request.groups = matcher.groups() #所有分组组成的元祖,包括命名分组 request.groupdict = matcher.groupdict() #命名分组组成的字典 return handler(request) raise HTTPNotFound('<h1>你访问的网页被外星人劫持了</h1>') if __name__ == '__main__': ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) try: server.serve_forever() except KeyboardInterrupt: server.shutdown() server.server_close()
Request Method过滤
1、在register装饰器中增加函参数
class Router: ROUTETABLE = [] @classmethod #注册路由,装饰器 def register(cls,method,pattern): def wrapper(handler): cls.ROUTETABLE.append((method.upper(),re.compile(pattern),handler)) return handler return wrapper @Router.register('GET',r'^/$') @Router.register('GET',r'^/(?P<id>d+)$') def indexhandler(request): return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.get('id'))
2、将register分解成不同方法的装饰器
class Router: ROUTETABLE = [] @classmethod #注册路由,装饰器 def register(cls,method,pattern): def wrapper(handler): cls.ROUTETABLE.append((method.upper(),re.compile(pattern),handler)) return handler return wrapper @classmethod def get(cls,pattern): return cls.register('GET',pattern)
from webob import Request,Response from webob.dec import wsgify from wsgiref.simple_server import make_server from webob.exc import HTTPNotFound import re class Router: ROUTETABLE = [] #列表,有序 @classmethod #注册路由,装饰器 def router(cls,method,pattern): def wrapper(handler): cls.ROUTETABLE.append((method.upper(),re.compile(pattern),handler)) return handler return wrapper @classmethod def get(cls,pattern): return cls.router('GET',pattern) @classmethod def post(cls,pattern): return cls.router('POST',pattern) @classmethod def head(cls,pattern): return cls.router('HEAD',pattern) @Router.get(r'^/$') @Router.router('GET',r'^/(?P<id>d+)$') def indexhandler(request): return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.get('id')) @Router.get(r'/python/d+') @Router.router('GET','^/python$') def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" class App: _Router = Router @wsgify def __call__(self, request:Request): for method,pattern,handler in self._Router.ROUTETABLE: if request.method in method or not method: matcher = pattern.match(request.path) #正则匹配 if matcher: #动态为request增加属性 request.groups = matcher.groups() #所有分组组成的元祖,包括命名分组 request.groupdict = matcher.groupdict() #命名分组组成的字典 return handler(request) raise HTTPNotFound('<h1>你访问的网页被外星人劫持了</h1>') if __name__ == '__main__': ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) try: server.serve_forever() except KeyboardInterrupt: server.shutdown() server.server_close()
改进
from webob import Request,Response from webob.dec import wsgify from wsgiref.simple_server import make_server from webob.exc import HTTPNotFound import re class Router: ROUTETABLE = [] #列表,有序 @classmethod #注册路由,装饰器 def router(cls,pattern,*methods): def wrapper(handler): cls.ROUTETABLE.append( (tuple(map(lambda x:x.upper(),methods)), re.compile(pattern), handler) ) return handler return wrapper @classmethod def get(cls,pattern): return cls.router(pattern,'GET') @classmethod def post(cls,pattern): return cls.router(pattern,'POST') @classmethod def head(cls,pattern): return cls.router(pattern,'HEAD') @Router.router(r'^/(?P<id>d+)$') #支持所有方法 @Router.get(r'^/$') def indexhandler(request): return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.get('id')) @Router.get(r'/python/d+') @Router.router('^/python$','GET') def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" class App: _Router = Router @wsgify def __call__(self, request:Request): for method,pattern,handler in self._Router.ROUTETABLE: if request.method in method or not method: matcher = pattern.match(request.path) #正则匹配 if matcher: #动态为request增加属性 request.groups = matcher.groups() #所有分组组成的元祖,包括命名分组 request.groupdict = matcher.groupdict() #命名分组组成的字典 return handler(request) raise HTTPNotFound('<h1>你访问的网页被外星人劫持了</h1>') if __name__ == '__main__': ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) try: server.serve_forever() except KeyboardInterrupt: server.shutdown() server.server_close()
路由分组***
from webob import Request,Response from webob.dec import wsgify from wsgiref.simple_server import make_server from webob.exc import HTTPNotFound import re class Router: def __init__(self,prefix:str=''): self._prefix = prefix self._routertable = [] # ROUTETABLE = [] #列表,有序 #注册路由,装饰器 def router(self,pattern,*methods): def wrapper(handler): self._routertable.append( (tuple(map(lambda x:x.upper(),methods)), re.compile(pattern), handler) ) return handler return wrapper def get(self,pattern): return self.router(pattern,'GET') def post(self,pattern): return self.router(pattern,'POST') def head(self,pattern): return self.router(pattern,'HEAD') def match(self,request:Request): #必须先匹配前缀 if not request.path.startswith(self._prefix): return None #前缀匹配,说明必须由这个Router实例处理 for method,pattern,handler in self._routertable: if request.method in method or not method: #前缀已经是以_prefix开头了,利用replace去掉前缀,且只需要替换一次 matcher = pattern.match(request.path.replace(self._prefix,'',1)) if matcher: #动态为request增加属性 request.groups = matcher.groups() #所有分组组成的元祖,包括命名分组 request.groupdict = matcher.groupdict() #命名分组组成的字典 return handler(request) class App: _Routers = [] #存储所有一级Router对象 #注册 @classmethod def register(cls,*routers:Router): for router in routers: cls._Routers.append(router) @wsgify def __call__(self, request:Request): for router in self._Routers: response = router.match(request) if response: return response raise HTTPNotFound('<h1>你访问的网页被外星人劫持了</h1>') #创建Router对象 python = Router('/python') index = Router('') #注册 App.register(index,python) @index.router(r'^/(?P<id>d+)$') #支持所有方法 http://127.0.0.1:9999/2134 @index.get(r'^/$') #http://127.0.0.1:9999/ def indexhandler(request): return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.get('id')) @python.router(r'^d+$') #支持所有方法 http://127.0.0.1:9999/python1234 @python.get(r'/python$') #http://127.0.0.1:9999/python/python def pythonhandler(request): return "<h1>欢迎来到python.html</h1>" if __name__ == '__main__': ip = '127.0.0.1' port = 9999 server = make_server(ip,port,App()) try: server.serve_forever() except KeyboardInterrupt: server.shutdown() server.server_close()
字典访问属性化
class AttriDict: def __init__(self,d:dict): self.__dict__.update(d if isinstance(d,dict) else {}) def __setattr__(self, key, value): raise NotImplementedError def __repr__(self): return "<Attrdict {}>".format(self.__dict__) d = {'a':1,'b':2} do = AttriDict(d) print(do.__dict__) print(do.a) print(do.b)
#1 class AttriDict: def __init__(self,d:dict): self.__dict__.update(d if isinstance(d,dict) else {}) def __setattr__(self, key, value): raise NotImplementedError #不允许修改属性 def __repr__(self): return "<Attrdict {}>".format(self.__dict__) def __len__(self): return len(self.__dict__) #2 class Router: def match(self,request:Request): #必须先匹配前缀 if not request.path.startswith(self._prefix): return None #前缀匹配,说明必须由这个Router实例处理 for method,pattern,handler in self._routertable: if request.method in method or not method: #前缀已经是以_prefix开头了,利用replace去掉前缀,且只需要替换一次 matcher = pattern.match(request.path.replace(self._prefix,'',1)) if matcher: #动态为request增加属性 request.groups = matcher.groups() #所有分组组成的元祖,包括命名分组 request.groupdict = AttriDict(matcher.groupdict()) #命名分组组成的字典 return handler(request) #3 @index.router(r'^/(?P<id>d+)$') #支持所有方法 http://127.0.0.1:9999/2134 @index.get(r'^/$') #http://127.0.0.1:9999/ def indexhandler(request): # return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.get('id')) return '<h1>欢迎来到index.html</h1>{}'.format(request.groupdict.id)
正则表达式的化简***
#类型字符串映射到正则表达式 TYPEPATTERNS = { 'str':r'[^/]+', 'word':r'w+', 'int':r'[+-]?d+', 'float':r'[+-]?d+.d+', 'any':r'.+' }
#类型字符串到python类型的映射 TYPECAST = { 'str':str, 'word':str, 'int':int, 'float':float, 'any':str }
import re #1 pattern = r'd+' repl = '' src = 'welcome 123 to 456' regex = re.compile(pattern) dest = regex.sub(repl,src) print(dest)#welcome to #2 pattern = r'/{([^{}:]+):?([^{}:]*)}' src = '/student/{name}/xxx/{id:int}' print(src) def repl(matcher): print(matcher.group(0)) print(matcher.group(1)) print(matcher.group(2)) #{name}或{name:}这个分组都匹配为'' return '/(?P<{}>{})'.format( matcher.group(1), 'T' if matcher.group(2) else 'F' ) regex = re.compile(pattern) dest = regex.sub(repl,src) print(dest) #/student/(?P<name>F)/xxx/(?P<id>T)
import re regex = re.compile(r'/{([^{}:]+):?([^{}:]*)}') s = [ '/student/{name:str}/xxx/{id:int}', '/student/xxx/{id:int}/yyy', '/student/xxx/6454654', '/student/{name:}/xxx/{id:aaa}', '/student/{name:}/xxx/{id:aaa}' ] TYPEPATTERNS = { 'str': r'[^/]+', 'word': r'w+', 'int': r'[+-]?d+', 'float': r'[+-]?d+.d+', 'any': r'.+' } def repl(matcher): return '/(?P<{}>{})'.format( matcher.group(1), TYPEPATTERNS.get(matcher.group(2),TYPEPATTERNS['str']) ) def parse(src:str): return regex.sub(repl,src) for x in s: print(parse(x)) #运行结果如下: # /student/(?P<name>[^/]+)/xxx/(?P<id>[+-]?d+) # /student/xxx/(?P<id>[+-]?d+)/yyy # /student/xxx/6454654 # /student/(?P<name>[^/]+)/xxx/(?P<id>[^/]+) # /student/(?P<name>[^/]+)/xxx/(?P<id>[^/]+)
将上面的代码合入Router类中
from webob import Request,Response from webob.exc import HTTPNotFound from webob.dec import wsgify from wsgiref.simple_server import make_server import re class AttrDict: def __init__(self,d:dict): self.__dict__.update(d if isinstance(d,dict) else {}) def __setattr__(self, key, value): #不允许修改属性 raise NotImplementedError def __repr__(self): return "<AttrDict {}>".format(self.__dict__) def __len__(self): return len(self.__dict__) class Router: __regex = re.compile(r'/{([^{}:]+):?([^{}:]*)}') TYPEPATTERNS = { 'str':r'[^/]+', 'word':r'w+', 'int':r'[+-]?d+', 'float':r'[+-]?d+.d+', 'any':r'.+' } def __repl(self,matcher): return '/(?P<{}>{})'.format( matcher.group(1), self.TYPEPATTERNS.get(matcher.group(2),self.TYPEPATTERNS['str']) ) def __parse(self,src:str): return self.__regex.sub(self.__repl,src) #####实例 def __init__(self,prefix:str=''): self.__prefix = prefix.rstrip('/\') #前缀,例如/product self.__routetable = [] #存三元组,列表,有序的 def route(self,pattern,*methods): #注册路由 def wrapper(handler): #/student/{name:str}/xxx/{id:int} ==> '/student/(?P<name>[^/]+/xxx/(?P<id>[+-]\d+))' self.__routetable.append( (tuple(map(lambda x:x.upper(),methods)), re.compile(self.__parse(pattern)), handler ) ) return handler return wrapper def get(self,pattern): return self.route(pattern,'GET') def post(self,pattern): return self.route(pattern,'POST') def head(self,pattern): return self.route(pattern,'HEAD') def match(self,request:Request): #必须先匹配前缀 if not request.path.startswith(self.__prefix): return None #前缀匹配,说明就必须这个Router实例处理,后续匹配不上,依然返回None for methods,pattern,handler in self.__routetable: # not methods表示一个方法都没有定义,就是支持全部方法 if not methods or request.method.upper() in methods: #前提是以__prefix开头了,可以replace,去掉prefix剩下的才是正则表达式需要匹配的路径 matcher = pattern.match(request.path.replace(self.__prefix,'',1)) if matcher:#正则匹配 #动态增加属性 request.groups = matcher.groups()#所有分组组成的元组,包括命名分组 request.groupdict =AttrDict(matcher.groupdict())#命名分组组成的字典被属性化 return handler(request) class App: _ROUTERS = [] #存储所有一级对象 #注册 @classmethod def register(cls,*routers:Router): for router in routers: cls._ROUTERS.append(router) @wsgify def __call__(self, request:Request): #遍历_ROUTERS,调用Router实例的match方法,进行匹配 for router in self._ROUTERS: response = router.match(request) if response: #匹配返回非None的Router对象 return response raise HTTPNotFound #创建Router对象 idx = Router() py = Router('/python') #注册 App.register(idx,py) @idx.get(r'^/$') @idx.route(r'^/{id:int}$') #支持所有方法 def indexhandler(request): id = '' if request.groupdict: id = request.groupdict.id return '<h1>magedu.com{}欢迎你</h1>'.format(id) @py.get(r'^/{id}$') def pythonhandler(request): res = Response() res.charset = 'utf-8' res.body = '<h1>welcome to Python</h1>'.encode() return res if __name__ == '__main__': ip = '127.0.0.1' port= 9999 server = make_server(ip,port,App) try: server.serve_forever() # server.handle_request() 一次 except KeyboardInterrupt: server.shutdown() server.server_close()
from webob import Request,Response from webob.exc import HTTPNotFound from webob.dec import wsgify from wsgiref.simple_server import make_server import re class AttrDict: def __init__(self,d:dict): self.__dict__.update(d if isinstance(d,dict) else {}) def __setattr__(self, key, value): #不允许修改属性 raise NotImplementedError def __repr__(self): return "<AttrDict {}>".format(self.__dict__) def __len__(self): return len(self.__dict__) class Router: __regex = re.compile(r'/{([^{}:]+):?([^{}:]*)}') TYPEPATTERNS = { 'str':r'[^/]+', 'word':r'w+', 'int':r'[+-]?d+', 'float':r'[+-]?d+.d+', 'any':r'.+' } TYPECAST = { 'str':str, 'word':str, 'int':int, 'float':float, 'any':str } def __parse(self,src: str): start = 0 repl = '' types = {} matchers = self.__regex.finditer(src) for i, matcher in enumerate(matchers): name = matcher.group(1) t = matcher.group(2) types[name] = self.TYPECAST.get(t, str) repl += src[start:matcher.start()] #拼接分组前 tmp = '/(?P<{}>{})'.format( matcher.group(1), self.TYPEPATTERNS.get(matcher.group(2), self.TYPEPATTERNS['str']) ) repl += tmp # 替换 start = matcher.end() #移动 else: repl += src[start:] # 拼接分组后的内容 return repl, types #####实例 def __init__(self,prefix:str=''): self.__prefix = prefix.rstrip('/\') #前缀,例如/product self.__routetable = [] #存四元组,列表,有序的 def route(self,rule,*methods): #注册路由 def wrapper(handler): #/student/{name:str}/xxx/{id:int} ==> '/student/(?P<name>[^/]+/xxx/(?P<id>[+-]\d+))' pattern,trans = self.__parse(rule) # 用户输入规则转换为正则表达式 self.__routetable.append( (tuple(map(lambda x:x.upper(),methods)), re.compile(pattern), trans, handler )#(方法元组,预编译正则对象,类型转换,处理函数) ) return handler return wrapper def get(self,pattern): return self.route(pattern,'GET') def post(self,pattern): return self.route(pattern,'POST') def head(self,pattern): return self.route(pattern,'HEAD') def match(self,request:Request): #必须先匹配前缀 if not request.path.startswith(self.__prefix): return None #前缀匹配,说明就必须这个Router实例处理,后续匹配不上,依然返回None for methods,pattern,trans,handler in self.__routetable: # not methods表示一个方法都没有定义,就是支持全部方法 if not methods or request.method.upper() in methods: #前提是以__prefix开头了,可以replace,去掉prefix剩下的才是正则表达式需要匹配的路径 matcher = pattern.match(request.path.replace(self.__prefix,'',1)) if matcher:#正则匹配 newdict = {} for k,v in matcher.groupdict().items(): newdict[k] = trans[k](v) #动态增加属性 request.groupdict =AttrDict(newdict)#命名分组组成的字典被属性化 return handler(request) class App: _ROUTERS = [] #存储所有一级对象 #注册 @classmethod def register(cls,*routers:Router): for router in routers: cls._ROUTERS.append(router) @wsgify def __call__(self, request:Request): #遍历_ROUTERS,调用Router实例的match方法,进行匹配 for router in self._ROUTERS: response = router.match(request) if response: #匹配返回非None的Router对象 return response raise HTTPNotFound('<h1>你访问的页面不存在!</h1>') #创建Router对象 idx = Router() py = Router('/python') #注册 App.register(idx,py) @idx.get(r'^/$') @idx.route(r'^/{id:int}$') #支持所有方法 def indexhandler(request): id = '' if request.groupdict: id = request.groupdict.id return '<h1>magedu.com{}欢迎你</h1>'.format(id) @py.get(r'^/{id}$') def pythonhandler(request): if request.groupdict: print(type(request.groupdict.id)) res = Response() res.charset = 'utf-8' res.body = '<h1>welcome to Python</h1>'.encode() return res if __name__ == '__main__': ip = '127.0.0.1' port= 9999 server = make_server(ip,port,App()) try: server.serve_forever() # server.handle_request() 一次 except KeyboardInterrupt: server.shutdown() server.server_close()
框架处理流程