上一篇文章对webpy启动进行了讲解,今天主要分析以下appliction.py这个文件的代码(webpy核心的主要功能就在这里面),以了解webpy对请求的处理过程。
我们在运用webpy时有两个特性可能注意到了,一个是子应用(在上一篇文章已经提及到),另外是"应用处理器"和“钩子”Wbepy-coobook资料里面提及到钩子的使用方法,我们可以先明白它们的使用方法后面一步一步分析其实现原理。
首先我们进入appliction.py的 def __init__(self, mapping=(), fvars={}, autoreload=None):方法webpy初始化就基本从这里开始了
def __init__(self, mapping=(), fvars={}, autoreload=None): if autoreload is None: autoreload = web.config.get('debug', False) self.init_mapping(mapping) self.fvars = fvars self.processors = [] #将appliction类自身的_load,_unload函数加入应用处理器 self.add_processor(loadhook(self._load)) self.add_processor(unloadhook(self._unload)) if autoreload:通过以上源码注释下的两行代码与钩子的使用方法比较可以看出它们是一样的,所以我们可以把"钩子"归一到"应用处理器"。
这里我们可以猜想到webpy里面很大一部分功能可能都是通过"processor"实现的,实际上在分析以下session.py代码以后就可以发现web.py的session处理就是通过加入一个processor实现的。processor可以理解为一个处理链条当请求到来时一步一步通过这个链条里面的processor处理。
下一步我们来了解当请求到来是webpy的执行过程,通过上一篇文章了解我们可以确定webpy其实是一个wsgi应用,webpy通过application.py 的run方法启动wsgi服务,并且传人自己的处理函数以供wsgi在有请求是回调处理。
def run(self, *middleware): return wsgi.runwsgi(self.wsgifunc(*middleware))通过以上代码可以确定回调函数就是从 self.wsgifunc(*middleware) 函数中取得的
def wsgifunc(self, *middleware): """Returns a WSGI-compatible function for this application.""" def peep(iterator): """Peeps into an iterator by doing an iteration and returns an equivalent iterator. """ # wsgi requires the headers first # so we need to do an iteration # and save the result for later try: firstchunk = iterator.next() except StopIteration: firstchunk = '' return itertools.chain([firstchunk], iterator) def is_generator(x): return x and hasattr(x, 'next') #本appliction处理回调函数,当请求到来时最先调用这个回调函数 def wsgi(env, start_resp): # clear threadlocal to avoid inteference of previous requests self._cleanup() #判断请求,提取请求的参数,状态等信息 self.load(env) try: # allow uppercase methods only if web.ctx.method.upper() != web.ctx.method: raise web.nomethod() #递归的调用已加入的"应用处理器" result = self.handle_with_processors() if is_generator(result): result = peep(result) else: result = [result] except web.HTTPError, e: result = [e.data] result = web.safestr(iter(result)) #处理完毕返回给用户 status, headers = web.ctx.status, web.ctx.headers start_resp(status, headers) def cleanup(): self._cleanup() yield '' # force this function to be a generator return itertools.chain(result, cleanup()) #将用户传人的应用处理器(上一篇文章最后实现的wsgi应用)加入到列表中 for m in middleware: wsgi = m(wsgi) return wsgi
分析以上代码 请求到来时将首先执行 def wsgifunc(self, *middleware):函数中def wsgi(env, start_resp):函数的代码,def wsgi(env, start_resp):又调用appliction.py的def handle_with_processors(self):函数递归调用执行"processors"的代码。
def handle_with_processors(self): def process(processors): try: if processors: p, processors = processors[0], processors[1:] return p(lambda: process(processors)) else: return self.handle() except web.HTTPError: raise except (KeyboardInterrupt, SystemExit): raise except: print >> web.debug, traceback.format_exc() raise self.internalerror() # processors must be applied in the resvere order. (??) return process(self.processors)如此完整的请求执行链条便基本完成了。
通过以上代码分析如果processors被递归执行完毕以后便执行self.handle()函数代码如下
def handle(self): #匹配与url对应的执行函数 fn, args = self._match(self.mapping, web.ctx.path) #执行查找到的函数 return self._delegate(fn, self.fvars, args)_match函数对匹配用户的url与我们配置的urls进行匹配查找正确的url处理函数。然后调用_delegate函数去执行
def _delegate(self, f, fvars, args=[]): def handle_class(cls): meth = web.ctx.method if meth == 'HEAD' and not hasattr(cls, meth): meth = 'GET' if not hasattr(cls, meth): raise web.nomethod(cls) tocall = getattr(cls(), meth) return tocall(*args) def is_class(o): return isinstance(o, (types.ClassType, type)) if f is None: #没有匹配 raise web.notfound() elif isinstance(f, application): #如果找到的是一个appliction(子应用) return f.handle_with_processors() elif is_class(f): return handle_class(f) elif isinstance(f, basestring): if f.startswith('redirect '):