一、__call__()
在app启动后,一旦uwsgi收到来自web server的请求,就会调用app,其实此时就是调用app的__call__(environ,start_response).
flask.py:
def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response)
二、wsgi_app()
当http请求从server发送过来的时候,他会启动__call__功能,这时候就启动了最关键的wsgi_app(environ,start_response)函数。
fask.py:
class Flask(_PackageBoundObject):
........
#请注意函数的说明,说得非常准确,这个wsgi_app是一个真正的WSGI应用
def wsgi_app(self, environ, start_response): #他扮演的是一个中间角色
"""The actual WSGI application. This is not implemented in
`__call__` so that middlewares can be applied without losing a
reference to the class. So instead of doing this::
app = MyMiddleware(app)
It‘s a better idea to do this instead::
app.wsgi_app = MyMiddleware(app.wsgi_app)
Then you still have the original application object around and
can continue to call methods on it.
:param environ: a WSGI environment
:param start_response: a callable accepting a status code,
a list of headers and an optional
exception context to start the response
"""
ctx = self.request_context(environ) #
ctx.push()
error = None
try:
try:
response = self.full_dispatch_request() #full_dispatch_request起到了预处理和错误处理以及分发请求的作用
except Exception as e:
error = e
response = self.make_response(self.handle_exception(e)) #如果有错误发生,则生成错误响应
return response(environ, start_response) #如果没有错误发生,则正常响应请求,返回响应内容
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
首先,你会看到ctx = self.request_context(environ)的语句,这个涉及到Flask使用了请求上下文和应用上下文的概念,结构为栈结构,这部分比较难,后面第二篇会单独写。
这里只需要理解为,上面语句产生的所用是生成了一个request请求对象以及包含请求信息在内的request context
进入wsgi_app的函数内部,生成了request对象和上下文环境之后,进入到try
我们看到,响应被赋值成了full_dispatch_request()方法的返回内容,所以我们来看一下full_dispatch_request方法
他首先会触发 try_trigger_before_first_request_function()方法
在方法内部 ---------->会触发 _got_first_request 属性,这个属性的返回值是True或者False. True的话就代表了程序开始处理请求了.
来看看 try_trigger_before_first_request_function()的代码,他的目的是,最后将_got_first_request属性置为True.
再来看看_got_first_request 的定义,他的默认值是False
他的定义中可以明显看到, if the application started,this attribute is set to True.
接着,当_got_first_request 属性被设置完以后,我们就需要再次回到 full_dispatch_request函数内部,继续往下走
下面一段代码是request_started.send(),他是继承自signal模块,大致作用是进行socket部分的功能,暂时不详细追溯。
preprocess_request()方法的话,主要是进行flask的hook钩子, before_request功能的实现,也就是在真正发生请求之前,有些事情需要提前做
Flask一共有4个hook钩子,另外再写吧
随后,继续往下走,来到了一个至 关 重 要的功能 dispatch_request()
为什么说至关重要,因为一个http请求到了这里,实际上已经完成了从wsgi部分的过渡,进入到了寻找响应的阶段了,一个请求通过url进来以后,app怎么知道要如何响应呢?
就是通过dispatch_request方法来进行请求判定和分发。
来看源码
中间不需要过多考虑,req = _request_ctx_stack.top.request 可以暂时理解为,将请求对象赋值给req
这里先简单讲下,每个url进来以后,他都会对应一个view_function
比如下面的一个简单视图函数,路径 ‘/‘ 对应的是index函数
但是,实际上当中是分2步走的,第一步是‘/‘对应的endpoint为‘index‘ ,第二部是endpoint ‘index‘ 对应到index()视图函数
这个也是放在第二篇文章里面具体写flask 路由的实现,这里暂时可以忽略中间步骤,只要知道URL----------->VIEW FUNCTION的逻辑步骤就ok
另外说下view_functions 是一个字典形式,他的key和value的关系是endpoint ------> view function
所以每个有效的URL进来,都能找到他对应的视图函数view function,取得返回值并赋值给 rv
比如上面简单的index,他取得的就是 ‘Hello world‘ 值
请求分发完成后,已经取得了返回的值,再看下一步是如何做
我们再次回到 full_dispatch_request方法内往下走
这时候,通过make_response函数,将刚才取得的 rv 生成响应,重新赋值response
再通过process_response功能主要是处理一个after_request的功能,比如你在请求后,要把数据库连接关闭等动作,和上面提到的before_request对应和类似。
之后再进行request_finished.send的处理,也是和socket处理有关,暂时不详细深入。
之后返回新的response对象
这里特别需要注意的是,make_response函数是一个非常重要的函数,他的作用是返回一个response_class的实例对象,也就是可以接受environ和start_reponse两个参数的对象
非 常 重 要!!!
Converts the return value from a view function to a real response object that is an instance of :attr:`response_class
终于快进行到了最后一步,流程走回到了wsgi_app的内部
下面这段是wsgi_app内部的代码
当response从刚刚的full_dispatch_request功能返回之后,函数会对这个response加上environ, start_response的参数并返回给Gunicorn
至此,一个HTTP从请求到响应的流程就完毕了.
总的来说,一个流程的关键步骤可以简单归结如下:
后一篇,将会记录一下flask的route实现,里面的url如何和endpoint对应起来,endpoint和view function又是如何对应起来
原文:https://www.cnblogs.com/skyflask/p/9194224.html