Flask Interpretation---Elementary introduction to flask basic Work Flow _1

Source: Internet
Author: User

Website has been written for a long time, and always want to analyze and analyze the operation of the flask, but the source is intermittent, but the recent state is good, the progress of a point, here to create a new category, specifically to say flask and the source of the content of the relationship, this preparation to roughly say the application of flask framework, The process of starting from an HTTP request to a response


Front-facing skill---WSGI

Before the specific reading source, here first need to say a concept, what is WSGI.


WSGI, full name Web server gateway Interface, or Python Web server gateway Interface, is a simple and easy-to-pass between a Web server and a Web application or framework defined for the Python language The interface used. Similar interfaces have appeared in many other languages since WSGI was developed.

The official definition of WSGI is the Python Web Server Gateway Interface. From the name it can be seen that this thing is a gateway, that is, gateways. The purpose of a gateway is to convert between protocols.

WSGI is a low-level interface between a Web server and a Web application or application framework to enhance the common denominator of portable web application development. WSGI is designed based on the existing CGI standards.

Many frameworks have their own WSGI servers, such as Flask,webpy,django, CherryPy, and so on. Of course, the performance is not good, the Web server comes with more testing purposes, the release of the use of the production environment of the WSGI server or the joint nginx do UWSGI.


People who have searched the Wsgi on the Internet should see a graph, the server on the left, the app on the right, and a link in the middle is wsgi.

However, I read the source code after the understanding and this is somewhat different, I personally think, actually should not write an app alone, because this wsgi is actually included in the app, the right side of the app should actually refer to the logic function, including the URL and view The correspondence between function.

So I personally understand the following picture of myself

Wsgi actually acts as an interface to accept the information passed by the server, and then invokes the view function in the background app to respond through this interface.





Wsgi specific functions

The above mentioned WSGI can play an interface function, front docking server, back docking app specific functions

Let's take a look at one of the simplest WSGI_APP implementations.

def application (environ, start_response):               #一个符合wsgi协议的应用程序写法应该接受2个参数    start_response (' OK ', [(' Content-type ', ' text/html ')])  #environ为http的相关信息, such as the request for first-class start_response is the response message    return [b ' 

However, as the app itself, even if you start the program, you can not pass parameters to application?

So, in fact, the invocation of application and the passing of 2 parameters is done by the server, such as Gunicorn.

And this is called application, in the Flask framework inside the name, called Wsgi_app, please see the following section of the source code.



Flask and Wsgi generating flask instances

Let's take a look at the operating instructions for generating flask applications, which are definitely familiar to people who have used them.

From flask Import Flaskapp = Flask (__name__)         #生成app实例 @app. Route ("/") def index ():        return ' Hello world '


In this way, a flask app generates a

But here is a concept must be clear, that is, when your Gunicorn received an HTTP request to call the app, he actually used the Flask __call__ method, this is very important!!!

Because how the __call__ method is written determines where your entire process begins.


Let's look at the source code for the __call__ method of flask class.

Class Flask (_packageboundobject):        #Flask类 # middle omit some code    def __call__ (self, Environ, start_response):    # __call__ method for flask instance        "" "Shortcut for:attr: ' Wsgi_app '.        " "" Return Self.wsgi_app (environ, start_response)  #注意他的return, when he returns, is actually called Wsgi_app this function


As a result, we know that when the HTTP request is sent from the server, he will start the __call__ function, and finally actually call the Wsgi_app function and Pass in Environ and start_response


Wsgi_app Definition of flask
Class Flask (_packageboundobject): #中间省略一些代码 #请注意函数的说明, very accurate, this wsgi_app is a true WSGI application Def wsgi_app (self, Enviro  N, start_response): #他扮演的是一个中间角色 "" "The actual WSGI application. This isn't implemented in ' __call__ ' So, middlewares can be applied without losing a reference to the C  Lass. So instead of doing this:: App = Mymiddleware (APP) It's a better idea to doing this instead:: AP P.wsgi_app = Mymiddleware (App.wsgi_app) then you still has the original application object around and can C        Ontinue to call methods on it.                               :p Aram environ:a WSGI Environment:p Aram 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)) #如果有错误发生, generates an error response return response (ENVI                Ron, Start_response) #如果没有错误发生, then responds to the request normally, returning the response content Finally:if Self.should_ignore_error (Error): Error = None Ctx.auto_pop (Error)


Ok, the function definition of this wsgi_app, basically contains the function of the whole process




Internal flow of Wsgi_app


First step: Generate request Requests object and request context environment

First, you will see the statement of CTX = Self.request_context (environ), which involves flask using the concept of the request context and the application context , the structure of the stack structure , This part is more difficult, the second post will be written separately.

It is only necessary to understand that the above statement is generated using a Request object and a request context containing the requested information.




Part Two: The process of requesting access to preprocessing, error handling, and request forwarding to the response

Inside the function of Wsgi_app, after generating the request object and the context, enter into the try

Response = Self.full_dispatch_request ()    


We see that the response is assigned to the return content of the Full_dispatch_request () method, so let's take a look at the full_dispatch_request method

Class Flask (_packageboundobject): #此处省略一些代码    def full_dispatch_request (self): "" "Dispatches the request and on        Top of that performs request pre and postprocessing as well as        HTTP exception catching and        error handling ...        Versionadded:: 0.7        "" "        self.try_trigger_before_first_request_functions ()  #进行发生真实请求前的处理        Try:            request_started.send (self)                     #socket部分的操作            RV = self.preprocess_request ()                 #进行请求的预处理            if RV is None:                RV = self.dispatch_request ()        except Exception as e:            RV = self.handle_user_exception (e)        Response = Self.make_response (RV)        response = self.process_response (response)        request_finished.send (self, Response=response)        return response

He will first trigger the Try_trigger_before_first_request_function () method

Inside the method----------> triggers the _got_first_request property, which returns a value of True or False. If True, the program begins processing the request .


Take a look at the code for Try_trigger_before_first_request_function (), whose purpose is to finally set the _got_first_request property to True.

Class Flask (_packageboundobject): #省略一些代码    def try_trigger_before_first_request_functions (self): "" "        called Before each request and would ensure the IT triggers        the:attr: ' Before_first_request_funcs ' and only exactly once per< C3/>application instance (which means process usually).        : internal: "" "        if self._got_first_request:            Return with        self._before_request_lock:            if self._got_first_request:                return to            func in Self.before _first_request_funcs:                func ()            self._got_first_request = True



And then look at the definition of _got_first_request, his default value is False

His definition can be seen clearly, if the application Started,this attribute is set to True.

Class Flask (_packageboundobject): #省略一些代码    @property    def got_first_request (self): ' "" This        attribute is Set to ' True ' if the application started handling the first        request ...        versionadded:: 0.8        "" "        return SE Lf._got_first_request


Then, when the _got_first_request property is set, we need to go back inside the full_dispatch_request function and continue down.

The following section of code is request_started.send (), he is inherited from the signal module, the general role is to carry out the socket part of the function, temporarily not detailed retrospective.

Preprocess_request () method, the main is to carry out flask hook hooks, before_request function implementation, that is, before the actual request, some things need to be done in advance

There are 4 hooks in flask, and write it again.


Then, continuing down, came a vital function dispatch_request ()

        Try:            request_started.send (self)            RV = self.preprocess_request ()            if RV is None:                RV = Self.dispatch_ Request ()


Why is it important, because an HTTP request is here, actually has completed the transition from the WSGI part, into the search for a response phase, a request through the URL came in, the app how to know how to respond?

is to use the Dispatch_request method to determine and distribute the request.


Step three: Request distribution Dispatch_request

Look at the source

Class Flask (_packageboundobject): #省略一些代码 def dispatch_request (self): #看函数定义, matches the URL and returns the value of        The view or error.  "" "Does the request dispatching.  Matches the URL and returns the return value of the the view or error handler.  This does not has a to is a response object.        In order to convert the return value to a proper response object, Call:func: ' Make_response '. .. Versionchanged:: 0.7 This no longer does the exception handling, this code is moved to the New:meth:        ' Full_dispatch_request '. "" "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) a nd Req.method = = ' OPTIONS ': Return self.mAke_default_options_response () # Otherwise dispatch to the handler for that endpoint return SELF.VIEW_FUNCTI Ons[rule.endpoint] (**req.view_args) #最终进入view_functions, take out the return value of the view function corresponding to the URL

The middle does not need too much consideration, req = _request_ctx_stack.top.request can be temporarily understood as, the request object is assigned to req

Here is a brief, after each URL comes in, he will correspond to a view_function

For example, the following is a simple view function, the path '/' corresponds to the index function

However, in fact, it is divided into 2 steps, the first step is '/' corresponding to the endpoint ' index ', the second is Endpoint ' index ' corresponding to the index () view function

This is also put in the second article specifically write flask routing implementation , here can temporarily ignore the intermediate step, as long as the URL----------->view function logical step is OK


@app. Route ('/') def index ():    return ' Hello world '


In addition, View_functions is a dictionary form , and the relationship between his key and value is endpoint------> View function

So every valid URL comes in and finds his corresponding view function, gets the return value and assigns the value to RV

Like the simple index above, he gets the ' Hello world ' value



After the request distribution is complete, the returned value has been obtained, and then the next step is how to do

We're back in the Full_dispatch_request method.

        Response = Self.make_response (RV)        response = self.process_response (response)        request_finished.send (self, Response=response)        return response


At this point, the RV generated response, which was just obtained, is re-assigned through the Make_response function response

Again through the Process_response function is mainly to deal with a after_request function, such as you after the request, the database connection to close the action, and the above mentioned before_request correspondence and similar.

After the processing of Request_finished.send, is also related to socket processing, temporarily not detailed in-depth.

The new response object is then returned

In particular, it is important to note that the Make_response function is a very significant function, and his role is to return an Response_class instance object, that is, an object that can accept Environ and start_reponse two parameters.


Very IMPORTANT!!!

Converts the return value from a view function to a real response object this is an instance of:attr: ' Response_class

Class Flask (_packageboundobject): #注意函数说明, converts the return value from view function to a real response object #省略一 Section Code def make_response (self, RV): "" "Converts the return value from a view function to a real response ob        Ject that's an instance of:attr: ' Response_class '. The following types is allowed for ' RV ':.        Tabularcolumns:: |p{3.5cm}|p{9.5cm}| ======================= ===========================================: attr: ' Response_class ' The object is returned Unchanged:class: ' str ' A response object is created with the string as Bo Dy:class: ' Unicode ' a response object is created with the string encoded to U Tf-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 ' was a string or an integer and ' head        ERs ' is a list or a dictionary with header values. ======================= ===========================================:p Aram rv:the return value from the view funct Ion..        Versionchanged:: 0.9 Previously a tuple is interpreted as the arguments for the response object. "" "status_or_headers = headers = None if Isinstance (rv, tuple): RV, Status_or_headers, Heade rs = rv + (None,) * (3-len (RV)) If RV is None:raise valueerror (' View function does not return a respon Se ') if isinstance (Status_or_headers, (dict, List)): headers, status_or_headers = Status_or_headers, Non E If not isinstance (RV, Self.response_class): # When we create a response object directly, we let the constructor # set the headers and S  Tatus. We do this because there can is # some extra logic involved when creating these objects with # Speci            FIC 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





Fourth step: Return to Wsgi_app Interior

Finally the final step, the process went back to the interior of the Wsgi_app

The following is the code inside the Wsgi_app

        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)


When response returns from the Full_dispatch_request function, the function adds Environ, start_response parameters to the response and returns to Gunicorn


At this point, an HTTP request-to-response process is complete.


In general, the key steps of a process can be simply summed up as follows:




Later, will record the flask of the route implementation, the URL of how to correspond with endpoint, endpoint and view function is how to correspond together




This article:

Http://docs.jinkan.org/docs/flask/api.html?highlight=wsgi_app#flask.Flask.wsgi_app

1190000004223296

Http://docs.gunicorn.org/en/stable/run.html







Flask Interpretation---Elementary introduction to flask basic Work Flow _1

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.