Flask 中一次请求到响应的流程

Posted Python开发者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask 中一次请求到响应的流程相关的知识,希望对你有一定的参考价值。


来源:伯乐在线 - 一窗昏晓_送流年

链接:http://python.jobbole.com/85047/


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,

    )


【今日微信公号推荐↓】

更多推荐请看



以上是关于Flask 中一次请求到响应的流程的主要内容,如果未能解决你的问题,请参考以下文章

一次请求到响应的整个流程

flask前后端数据通信流程

flask 数据通信的流程 前后端刷新的方法

Flask解读 --- 浅谈Flask基本工作流程_1

flask请求流程详解

python 初步认识Flask