Flask中一次请求到响应的流程,flask响应,未经作者许可,禁止转载!


本文作者: 编橙之家 - 王海波 。未经作者许可,禁止转载!
欢迎加入编橙之家 专栏作者。

1、首先根据WSGI发送的environ变量获取请求上下文,主要是根据函数ctx = self.request_context(environ),然后将该请求上下文推入全局变量_request_ctx_stack中(ctx.push()).

def request_context(self, environ):
    return RequestContext(self, environ)

2、得到请求后,要触发第一次请求函数,如果是该应用是第一次实例化,并存在第一次请求之前函数(存在before_first_req_func字典中中),会调用存在该字典中的函数。当然一个实例也只执行一次,即在初始化的时候执行。

3、会发送请求开始信号,request_started,告知subscriber请求开始了。

4、如果存在before_request装饰的函数(函数位置在before_request_func字典中),那么在调用正常请求前会调用该函数。

@setupmethod
def before_request(self, f):
    """Registers a function to run before each request.
The function will be called without any arguments.
If the function returns a non-None value, it's handled as
if it was the return value from the view and further
request handling is stopped.
"""
self.before_request_funcs.setdefault(None, []).append(f)
return f

从函数可以看到,这是一个装饰器,被该装饰器修饰的函数会添加到字典中。

5、调用正常的请求,返回一个该请求函数的值。 调用请求的源代码:

def dispatch_request(self):
    """Does the request dispatching.  Matches the URL and returns the
    return value of the view or error handler.  This does not have to
    be a response object.  In order to convert the return value to a
    proper response object, call :func:make_response.
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
    self.raise_routing_exception(req)
rule = req.url_rule
# if we provide automatic options for this URL and the
# request came with the OPTIONS method, reply automatically
if getattr(rule, 'provide_automatic_options', False) 
   and req.method == 'OPTIONS':
    return self.make_default_options_response()
# otherwise dispatch to the handler for that endpoint
return self.view_functions[rule.endpoint](**req.view_args)

6、将请求函数返回值构造成响应类。

def make_response(self, rv):
    """Converts the return value from a view function to a real
    response object that is an instance of :attr:response_class.
The following types are allowed for `rv`:


======================= ===========================================
:attr:`response_class`  the object is returned unchanged
:class:`str`            a response object is created with the
                        string as body
:class:`unicode`        a response object is created with the
                        string encoded to utf-8 as body
a WSGI function         the function is called as WSGI application
                        and buffered as response object
:class:`tuple`          A tuple in the form ``(response, status,
                        headers)`` or ``(response, headers)``
                        where `response` is any of the
                        types defined here, `status` is a string
                        or an integer and `headers` is a list or
                        a dictionary with header values.
======================= ===========================================

:param rv: the return value from the view function

.. versionchanged:: 0.9
   Previously a tuple was interpreted as the arguments for the
   response object.
"""
status_or_headers = headers = None
if isinstance(rv, tuple):
    rv, status_or_headers, headers = rv + (None,) * (3 - len(rv))

if rv is None:
    raise ValueError('View function did not return a response')

if isinstance(status_or_headers, (dict, list)):
    headers, status_or_headers = status_or_headers, None

if not isinstance(rv, self.response_class):
    # When we create a response object directly, we let the constructor
    # set the headers and status.  We do this because there can be
    # some extra logic involved when creating these objects with
    # specific values (like default content type selection).
    if isinstance(rv, (text_type, bytes, bytearray)):
        rv = self.response_class(rv, headers=headers,
                                 status=status_or_headers)
        headers = status_or_headers = None
    else:
        rv = self.response_class.force_type(rv, request.environ)

if status_or_headers is not None:
    if isinstance(status_or_headers, string_types):
        rv.status = status_or_headers
    else:
        rv.status_code = status_or_headers
if headers:
    rv.headers.extend(headers)

return rv

7、会调用after_request装饰的函数,并返回响应类。 源代码:

def process_response(self, response):
    """Can be overridden in order to modify the response object
    before it's sent to the WSGI server.  By default this will
    call all the :meth:after_request decorated functions.
:param response: a :attr:`response_class` object.
:return: a new response object or the same, has to be an
         instance of :attr:`response_class`.
"""
ctx = _request_ctx_stack.top
bp = ctx.request.blueprint
funcs = ctx._after_request_functions
if bp is not None and bp in self.after_request_funcs:
    funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
if None in self.after_request_funcs:
    funcs = chain(funcs, reversed(self.after_request_funcs[None]))
for handler in funcs:
    response = handler(response)
if not self.session_interface.is_null_session(ctx.session):
    self.save_session(ctx.session, response)
return response

8、发送请求结束信号,request_finished.

9、应用将响应发送给客户端,利用响应函数response(environ, start_response)。

………………………………………………………………

下面是Flask请求响应的主函数:

def wsgi_app(self, environ, start_response):
    """The actual WSGI application.  
: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()
    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)

def call(self, environ, start_response):
    """Shortcut for :attr:wsgi_app."""
    return self.wsgi_app(environ, start_response)
def repr(self):
    return '' % (
        self.class.name,
        self.name,
    )

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

评论关闭