Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the Flask request processing flow?

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly explains "what is the flow of Flask request processing". Interested friends may wish to take a look at it. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "what is the Flask request processing flow?"

Flask

The processing flow of handler. (routing)

ThreadedWSGIServer. (multithreaded non-blocking server)

How to ensure request security by multithreading. (ctx)

1.flask handler execution process: # 1.wsgi phase WSGI-> Flask (). _ _ call__# 2.Flask phase wsgi_app ()-> full_dispatch_request ()-> dispatch_request ()-> view_handler () full_dispatch_request: framework implementation. 1. Request encapsulation, request ctx to stack 2. Trigger hook function. (try_trigger_before_first_request_functions) 3. Send a request to start signal. (request_started.send (self)) 4. Trigger dispatch_request. Call to the user's handlerview_handler: written by the user to implement the business 1.1 WSGI: the interface to implement the gateway protocol

Call (environ, start_response))

Flask.app.py implements the wsgi interface. (online can be hosted behind uwsgi/gunicorn)

Class Flask (_ PackageBoundObject): def dispatch_request (self): # 1. Get the request from the top of the _ request_ctx_stack stack. Req = _ request_ctx_stack.top.request if req.routing_exception is not None: self.raise_routing_exception (req) # 2.Rule object contains the mapping from url to viewhandler rule = req.url_rule #... # 3. Take out the handler and execute return self.view_ functions [rule.rules] (* * req.view_args) def full_dispatch_request (self): # 1. Trigger first_request_functions self.try_trigger_before_first_request_functions () try: # 2. Send request_started signal, trigger all registered signal function request_started.send (self) # 3. Preprocessing request rv = self.preprocess_request () if rv is None: # 4. To process the request, call the corresponding method rv = self.dispatch_request () except Exception as e: rv = self.handle_user_exception (e) # 5. End request return self.finalize_request (rv) def wsgi_app (self, environ, start_response): # 1. Request encapsulation ctx ctx = self.request_context (environ) error = None try: try: # 2.ctx stack ctx.push () response = self.full_dispatch_request () except Exception as e: error = e response = self.handle_exception (e) except: # noqa: B001 error = sys.exc_info () [1] raise return response (environ Start_response) finally: if self.should_ignore_error (error): error = None # 3.ctx automatic unstack ctx.auto_pop (error) def _ call__ (self, environ, start_response): return self.wsgi_app (environ, start_response) 1.2View CBV: implement dispatch interface. Complete the call from the http method to CBV.meth.

View: base view class.

Implement as_view

Dispatch_request: subclass implementation

MethodViewType: method view metaclass.

Cls.methods = methods bind method set to class properties

MethodView (with_metaclass (MethodViewType, View)): CBV

Flask.views.py

Http_method_funcs = frozenset (["get", "post", "head", "options", "delete", "put", "trace", "patch"]) class View (object): "" class MyView (View): methods = ['GET'] def dispatch_request (self) Name): return 'Hello%% name app.add_url_rule (' / hello/', view_func=MyView.as_view ('myview')) "methods = None provide_automatic_options = None decorators = () def dispatch_request (self): raise NotImplementedError () @ classmethod def as_view (cls, name, * class_args, * * class_kwargs): def view (* args) * * kwargs): # 1 Instantiate the view class self = view.view_class (* class_args, * * class_kwargs) # 2. Trigger dispatch_request return self.dispatch_request (* args * * kwargs) # registered decorator if cls.decorators: view.__name__ = name view.__module__ = cls.__module__ for decorator in cls.decorators: view = decorator (view) view.view_class = cls view.__name__ = name view.__doc__ = cls.__doc__ view.__module__ = cls.__module__ view.methods = cls.methods view.provide_automatic_options = cls.provide_automatic_options # function for route registration. It forms a mapping with url. Recorded in Flask (). Views_functions return viewclass MethodViewType (type): def _ _ init__ (cls, name, bases, d): super (MethodViewType, cls). _ _ init__ (name, bases, d) # 1.cls if "methods" not in d: methods = set () for base in bases: if getattr (base, "methods") without methods None: methods.update (base.methods) for key in http_method_funcs: if hasattr (cls, key): methods.add (key.upper ()) if methods: # 2. Bind the methods attribute to the current cls cls.methods = methodsclass MethodView (with_metaclass (MethodViewType, View)): "A class-based view that dispatches request methods to the corresponding class methods. For example, if you implement a ``get`` method, it will be used to handle ``GET`` requests. :: class CounterAPI (MethodView): def get (self): return session.get ('counter', 0) def post (self): session [' counter'] = session.get ('counter', 0) + 1 return' OK' app.add_url_rule ('/ counter') View_func=CounterAPI.as_view ('counter') "def dispatch_request (self, * args, * * kwargs): # 1. Get the view instance's meth meth = getattr (self, request.method.lower (), None) if meth is None and request.method = = "HEAD": meth = getattr (self, "get", None) assert meth is not None, "Unimplemented method% r"% request.method # 2. Execute methd return meth (* args, * * kwargs) 1.3 Blueprint blueprints

Implement routing.

Auth_view.py

Auth = Blueprint ('auth', _ name__) # bind / api/auth/login to login function, support GET,POST@auth.route (' / login', methods= ['GET',' POST']) def login (): pass# CBVclass Files (views.MethodView): methods= ['POST',' GET', 'PUT'] decorators = [auth_decorator] def get (self, * args) * * kwargs): pass def post (self, * args, * * kwargs): pass def put (self, * args, * * kwargs): passauth.add_url_rule ('/ files', view_func=Files.as_view (name='files'))

Main.py

From auth_view import authapp = Flask (_ _ name__) app.register_blueprint (auth, url_prefix='/api/auth') 2.flask server

The server of the development environment. (default: ThreadedWSGIServer)

The multithreaded server starts. Each establishes a connection and creates a thread to process the request.

WSGIRequestHandler: processing requests, encapsulation (environ, start_response)

Flask () .call (environ, start_response): executed

2.1 Development server startup process .app.run-> run_simple-> inner ()-> ThreadedWSGIServer () .serve_forever ()-> BaseWSGIServer () .serve_forever ()-> HTTPServer () .serve_forever ()-> TCPServer () .serve_forever ()-> BaseServer () serve_forever ()

Flask.server.py

# app.run () class Flask (_ PackageBoundObject): def run (self, host=None, port=None, debug=None, load_dotenv=True, * * options): options.setdefault ("use_reloader", self.debug) options.setdefault ("use_debugger", self.debug) options.setdefault ("threaded", True) try: run_simple (host, port, self) * * options) finally: self._got_first_request = False

SocketServer.py: standard library implementation

Serve_forever: server starts, waiting for request

Process_request: processing requests

Class BaseServer: def _ handle_request_noblock (self): "" Handle one request, without blocking. I assume that select.select has returned that the socket is readable before this function was called, so there should be no risk of blocking in get_request (). "" Try: request, client_address = self.get_request () except socket.error: return if self.verify_request (request, client_address): try: # call ThreadingMixIn () .process_request to process the request. Self.process_request (request, client_address) except: self.handle_error (request, client_address) self.shutdown_request (request) def serve_forever (self, poll_interval=0.5): "" Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. " Self.__is_shut_down.clear () try: while not self.__shutdown_request: r, w, e = _ eintr_retry (select.select, [self], [] Poll_interval) if self in r: self._handle_request_noblock () finally: self.__shutdown_request = False self.__is_shut_down.set () class TCPServer (BaseServer): passclass HTTPServer (SocketServer.TCPServer): pass2.2 WSGIRequestHandler handles the request

Werkzeug.serving.py: implement the processing of requests for wsgi protocol

{"wsgi.multiprocess": False, "HTTP_COOKIE": "csrftoken= Gfsessionid= "," SERVER_SOFTWARE ":" Werkzeug/0.16.0 "," SCRIPT_NAME ":", "REQUEST_METHOD": "GET", "PATH_INFO": "/ api/auth/login", "SERVER_PROTOCOL": "HTTP/1.1", "werkzeug.server.shutdown":, "HTTP_CONNECTION": "keep-alive", "werkzeug.request":, "wsgi.input": "wsgi.multithread": True, "REQUEST_URI": "/ api/auth/login?username=test&password=test", "wsgi.version": "(1,0)", "REMOTE_ADDR": "127.0.0.1", "HTTP_ACCEPT_ENCODING": "gzip, deflate".} class WSGIRequestHandler (BaseHTTPRequestHandler, object): def run_wsgi (self): # 1. Read the data of socket and encapsulate it as wsgi env self.environ = environ = self.make_environ () def execute (app): # 2. Call Flask (). _ _ call__ () to trigger the request flow application_iter = app (environ, start_response) try: for data in application_iter: write (data) if not headers_sent: write (b "") finally: if hasattr (application_iter "close": application_iter.close () application_iter = None try: execute (self.server.app) except (_ ConnectionError, socket.timeout) ase: self.connection_dropped (e, environ) except Exception: if self.server.passthrough_errors: raise passclass BaseWSGIServer (HTTPServer Object): "" single thread Single-process wsgi server "" def init (): handler = WSGIRequestHandler # handler HTTPServer.__init__ (self, server_address, handler) class ThreadedWSGIServer (ThreadingMixIn, BaseWSGIServer) that binds the wsgi request to the http server: "" A WSGI server that does threading. "" Multithread = True daemon_threads = Truedef make_server (): return ThreadedWSGIServer (host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd) def inner (...): srv = make_server () # start the server srv.serve_forever ()

App.run process:

-> srv.serve_forever ()-> ThreadedWSGIServer (). Serve_forever ()-> BaseServer () .serve_forever () 2.3 ThreadingMixIn multithreaded processing requests

ThreadingMixIn: implements the process_request interface. The promoter thread processes the current request

Class ThreadingMixIn: "Mix-in class to handle each request in a new thread." Daemon_threads = False def process_request_thread (self, request, client_address) try: self.finish_request (request, client_address) self.shutdown_request (request) except: self.handle_error (request, client_address) self.shutdown_request (request) def process_request (self, request Client_address): t = threading.Thread (target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start ()

Serve_forever uses non-blocking processing of the request. Once the request can be processed, execute self.process_request and call ThreadingMixIn (). Process_request ()

Start a new thread to process the request.

The main thread continues to execute serve_forever ()

Start the execution process of the new thread. (trigger Flask () .call ())

1.process_request_thread () 2.self.finish_request (request, client_address)-> BaseServer (). Finish_request (self, request, client_address):-> self.RequestHandlerClass (request, client_address, self)-> WSGIRequestHandler (). Handle ()-> WSGIRequestHandler (). Run_wsgi ()-> app (environ) Start_response) # Flask (). _ _ call__ () 3.self.shutdown_request (request) 5.ctx local

Referenc

Werkzeug.local.py

Local

LocalProxy

LocalStack

LocalManager when using the thread model, get_ident gets the thread identity. When using greenlet, get_ident gets the co-program identity.

Try: from greenlet import getcurrent as get_identexcept ImportError: try: from thread import get_identexcept ImportError: from _ thread import get_identclass Local (object): _ _ slots__ = ("_ _ storage__", "_ _ ident_func__") def _ _ init__ (self): object.__setattr__ (self, "_ storage__", {}) object.__setattr__ (self "_ _ ident_func__", get_ident) def _ _ iter__ (self): return iter (self.__storage__.items ()) def _ call__ (self, proxy): "" Create a proxy for a name. "" Return LocalProxy (self, proxy) def _ _ release_local__ (self): self.__storage__.pop (self.__ident_func__ (), None) def _ getattr__ (self, name): try: return self.__storage__ [self. _ ident_func__ ()] [name] except KeyError: raise AttributeError (name) def _ setattr__ (self, name) Value): ident = self.__ident_func__ () storage = self.__storage__ try: storage [ident] [name] = value except KeyError: storage [ident] = {name: value} def _ _ delattr__ (self Name): try: del self.__storage__ [self. _ _ ident_func__ ()] [name] except KeyError: raise AttributeError (name)

Flask.globals.py

_ request_ctx_stack: request context stack

_ app_ctx_stack: app context stack

Current_app: current request, starting multiple Flask () at the same time

Request

Session

G

# context locals_request_ctx_stack = LocalStack () _ app_ctx_stack = LocalStack () current_app = LocalProxy (_ find_app) request = LocalProxy (partial (_ lookup_req_object, "request")) session = LocalProxy (partial (_ lookup_req_object, "session")) g = LocalProxy (partial (_ lookup_app_object, "g"))

Can py3 context be replaced by: context

At this point, I believe you have a deeper understanding of "what is the Flask request processing flow?" you might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report