在框架中最核心的功能就是动态路由,通过动态路由功能才可以将指定访问的路径关联到对应的逻辑处理函数中处理并返回,所以在项目启动的时候就需要将逻辑函数与对应url关联到框架中。通过借鉴目前主流Web框架的做法以及为了更直观的体现MVC模式的应用,在自定义轻量级Web框架中采用了CBV的模式。CBV模式通俗点说就是通过类的方式组织代码将客户端的请求通过反射的方式对应到请求的逻辑函数中,代码实例如下 :
class UserloginHandler(BaseHandler) :
def get(self,request,*args,**options):
pass
def post(self,request,*args,**options):
pass
那么CBV模式的是如何实现的 ?下面的实例代码给了非常详细的解释 : 编写的逻辑函数类继承BaseHandler
的时候,当客户端请求发送过来的时候会携带请求的方法,执行BaseHandler
函数的dispatch_request
进行请求的转发,在BaseHandler
类的dispatch_request
方法中,通过Python内置的自省函数getattr
响应了请求的方法的类型,执行请求类型对应的方法:通俗理解就是如果客户端的请求方法为Get类型,那么执行def get(self,request,*args,**options)
方法,如果客户端请求方法为Post类型,那么执行def post(self,request,*args,**options)
方法。
class Handler :
def dispatch_request(self,request,*args,**options):
raise NotImplementedError
@classmethod
def get_func(cls,name):
def func(*args,**options) :
return cls().dispatch_request(*args,**options)
func.__name__ = name
func.__doc__ = cls.__doc__
func.__module__ = cls.__module__
func.methods = cls.methods
return func
class BaseHandler(Handler) :
methods = {'GET','POST'}
def dispatch_request(self,request,*args,**options):
if request.method in self.methods :
func = getattr(self,request.method.lower())
return func(request,*args,**options)
return
def get(self,request,*args,**options):
pass
def post(self,request,*args,**options):
pass
那么在框架中如何调用CBV的方式,其实预先在框架中绑定了三个方法 :load_handler
,load_controller
,add_rule_url
,在编写逻辑函数类的时候的实现用例如下图所示 :
app = SyncServiceHandler()
class TemplateRevealHander(BaseHandler) :
def get(self,request,*args,**options):
pass
def post(self,request,*args,**options):
pass
url_rule_map = [
{
'url' : '/templates',
'handler': TemplateRevealHander,
'endpoint' : 'template',
},
]
controller = Controller('self',url_rule_map)
app.load_controller(controller)
app.run()
其中add_rule_url
函数是整个框架不可或缺的一部分,该函数的目的就是为了关联url与端点函数的映射以及端点函数与保存视图函数相关数据结构的映射,这两种映射之间的关系是通过Python自带的数据结构{ }建立关联。
class BaseCacheModel :
#保存逻辑函数的数据结构
def __init__(self,func,func_class,**options):
self.func = func
self.func_class = func_class
self.options = options
def add_rule_url(self,url,func,func_class,endpoint = None,**options):
if endpoint is None :
endpoint = func.__name__
if url in self.urls_maps :
raise
if endpoint in self.func_maps and not isinstance(func_class,InactialModel) :
raise
self.urls_maps[url] = endpoint
self.func_maps[endpoint] = BaseCacheModel(func,func_class,**options)
建立端点函数与保存视图函数逻辑数据结构的目的就是为了在请求转发过程中区别于静态类型的视图函数。这样说可能有点突兀,在以后的章节中会详细解释。
测试用例 :
-
对.mp3静态文件的响应,在浏览器中输入http://127.0.0.1:8000/music,网页中会渲染出音乐播放的界面
-
对.jpg静态文件的响应,在浏览器中输入http://127.0.0.1:8000/image,浏览器中会渲染出图片的文件
-
对.js静态文件的响应,在浏览器中输入http://127.0.0.1:8000/js,浏览出弹出窗口