前景
上一次我梳理了下,一个app最基本的流程,今天来看一下WSGI是如何去处理请求的
WSGI请求处理
上一部分的WSGIRequestHandler虽然是作为request的处理,但是实际上处理的并不是它而是调用的app()这个函数,传递给它environ和start_response,我们进app.py这个文件一探究竟
__call__
def __call__(self, environ, start_response):
"""Shortcut for :attr:`wsgi_app`."""
return self.wsgi_app(environ, start_response)
源码最后写了一个call方法,将自己作为函数可被调用,最后调用wsgi_app这个方法
wsgi_app
def wsgi_app(self, environ, start_response):
# 创建请求的上下文,并把它push压入栈
ctx = self.request_context(environ)
ctx.push()
error = None
try:
try:
# 处理http请求的业务逻辑,分发请求到视图函数上
response = self.full_dispatch_request()
# 异常处理
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# 不管处理是否发生异常,将栈中的请求pop出来
ctx.auto_pop(error)
full_dispatch_request
def full_dispatch_request(self):
"""
分发请求,并且在这之前进行请求预处理和后处理并且处理HTTP异常和错误
"""
self.try_trigger_before_first_request_functions()
try:
# 发出信号,表示请求处理开始
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)
try_trigger_full_dispatch_request_functions
处理flask中berfore_first_request的
def try_trigger_before_first_request_functions(self):
# 在每次request时调用,保证能触发before_request_funcs,并且对于一个实例只能触发一次
# 实际上就是是否是第一个请求,第一次请求前,self._got_first_request = False,
if self._got_first_request:
return
# 一个加锁的操作
with self._before_request_lock:
if self._got_first_request:
return
for func in self.before_first_request_funcs:
func()
# 执行完毕之后,会改为True,表示不再是第一次了
self._got_first_request = True
接下来是预处理 * preprocess_request()*:预处理函数,处理的是被before_request装饰的函数。也就是在每个请求之前会被调用的一个函数,flask中的钩子函数就是这么处理的
def preprocess_request(self):
"""
在真实请求分发前调用,会调用before_request装饰的函数,不传递参数。
如果其中任何一个函数返回了值,那么就把这个值当成了视图函数的返回,后续的请求处理将会停止。
这也会触发url_value_preprocessor函数,在before_request函数之前调用
"""
bp = _request_ctx_stack.top.request.blueprint
funcs = self.url_value_preprocessors.get(None, ())
if bp is not None and bp in self.url_value_preprocessors:
funcs = chain(funcs, self.url_value_preprocessors[bp])
for func in funcs:
func(request.endpoint, request.view_args)
funcs = self.before_request_funcs.get(None, ())
if bp is not None and bp in self.before_request_funcs:
funcs = chain(funcs, self.before_request_funcs[bp])
for func in funcs:
rv = func()
if rv is not None:
return rv
解读:
其实就是触发url_value_preprocessor,和before_request之后才会执行这个函数。因为它先从这两个里面get,获取,如果有才执行。默认里面self.url_value_preprocessors = {} 和self.before_request_funcs = {},这两个都是空的,所以我们暂时可以先不看
总结作用:就是两个函数的预处理,触发了就执行,没有就不执行
rv = self.dispatch_request()
def dispatch_request(self):
"""
执行request的分发,匹配URL返回视图函数的值,不必成为一个response对象,可以调用make_response,转变返回值使之成为一个response
"""
# 从栈中读取request,而不是通过参数
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
# 如果提供了automatic 选项给URL并且,request来自options方法,自动回复
if getattr(rule, 'provide_automatic_options', False) \
and req.method == 'OPTIONS':
return self.make_default_options_response()
# 否则分发到路由函数上
return self.view_functions[rule.endpoint](**req.view_args)
解读一下:
我们可以看到,这个函数最终返回的是一个url endpoint(‘/’,’/index’)之类的和视图函数的映射字典 self.view_functions = {},
request最终处理:finalize_request
def finalize_request(self, rv, from_error_handler=False):
"""
因为已经从视图函数中得到了返回值,所以最终将request打包成一个response
"""
# make_response,将视图函数中的返回值打包成为一个真正的response对象
response = self.make_response(rv)
try:
# process_response()是一个after_resuqest处理函数,在有after_request后进行触发
response = self.process_response(response)
# 发出结束的信号
request_finished.send(self, response=response)
except Exception:
if not from_error_handler:
raise
self.logger.exception('Request finalizing failed with an '
'error while handling an error')
return response
总结作用:
这个函数就是给WSGIRequestHandler,也就是给WSGI服务器返回最终response的函数,到这里一个完整的WSGI的request处理就结束了,至于怎么make_response那是app的事情。
总结
真实的WSGI应用实际上是在app中的,WSGIRequestHandler把环境和start_response传给app,然后app里面的wsgi_app来把request分发到视图上的。然后最后进行response的打包。WSGI真正的流程是这个样子。终于搞清楚简单的流程了-。-明天去看看上下文的处理