当前位置:网站首页>Flask1.1.4 werkzeug1.0.1 source code analysis: start the process
Flask1.1.4 werkzeug1.0.1 source code analysis: start the process
2022-07-07 05:52:00 【An engineer$】
be based on QuickStart One of them demo To analyze
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
if __name__ == '__main__':
app.run()
@app.route(“/”) Is a decorator factory function that receives parameters , Returns a decorator that closes a specific parameter
# flask/app.py L1288
def route(self, rule, **options):
# Typical registration decorator
def decorator(f):
endpoint = options.pop("endpoint", None)
# This method will url Information and view_func Sign up to flask In the example
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
The key is self.add_url_rule(rule, endpoint, f, **options) Method The following code has been simplified
# flask/app.py L1178
@setupmethod
def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
# here endpoint It's an important concept The following will be explained in detail in the routing section
# stay flask Medium is url_map and view_functions An important link of connection
# Every time a request comes Go to url_map Search for endpoint,args Then go view_functions[endpoint](args) Get the results
# If not The default is view_func.__name__
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint
methods = options.pop("methods", None)
# ...
# Here url_rule_class It's a Flask Class properties The value is werkzeug.routing.Rule
# So here is build werkzeug.routing.Rule object
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options
# Well constructed rule Object to save to url_map Instance properties
# url_map yes werkzeug.routing.Map object
# flask The routing part actually relies on werkzeug The ability of
self.url_map.add(rule)
if view_func is not None:
# ...
# endpoint by key The corresponding view_func Save in view_functions Properties of the
# view_functions It's a dict
self.view_functions[endpoint] = view_func
It's simple ,add_url_rule The main function is take rule and view_func Information maintenance to flask Example of url_map and view_functions Properties of the
ok, Continue to study app.run() The starting process is among them (app.run() Will start a simple web The server is used for development and testing , The production environment will use other high-performance web server, However, with the help of this research, it is still possible to start the process )
# flask/app.py L889
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
# ...
from werkzeug.serving import run_simple
try:
# With the help of werkzeug.serving.run_simple
# Notice the third parameter take flask The example was passed to run_simple Method
# follow-up web server Would call flask Instance for logical processing
run_simple(host, port, self, **options)
finally:
# reset the first request information if the development server
# reset normally. This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
self._got_first_request = False
Then look at run_simple Code , Switch to research werkzeug Source code
# werkzeug/serving.py L876
def run_simple(
hostname,
port,
application,
use_reloader=False,
use_debugger=False,
use_evalex=True,
extra_files=None,
reloader_interval=1,
reloader_type="auto",
threaded=False,
processes=1,
request_handler=None,
static_files=None,
passthrough_errors=False,
ssl_context=None,
):
#...
# application The parameter corresponds to flask example
def inner():
try:
fd = int(os.environ["WERKZEUG_SERVER_FD"])
except (LookupError, ValueError):
fd = None
# This is the key Create a server example
srv = make_server(
hostname,
port,
application,
threaded,
processes,
request_handler,
passthrough_errors,
ssl_context,
fd=fd,
)
if fd is None:
log_startup(srv.socket)
# call web server Example of serve_forever Method
srv.serve_forever()
if use_reloader:
#...
else:
inner()
Keep going , First look at make_server Method
# werkzeug/serving.py L830
def make_server(
host=None,
port=None,
app=None,
threaded=False,
processes=1,
request_handler=None,
passthrough_errors=False,
ssl_context=None,
fd=None,
):
if threaded and processes > 1:
raise ValueError("cannot have a multithreaded and multi process server.")
elif threaded:
return ThreadedWSGIServer(
host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd
)
elif processes > 1:
return ForkingWSGIServer(
host,
port,
app,
processes,
request_handler,
passthrough_errors,
ssl_context,
fd=fd,
)
else:
return BaseWSGIServer(
host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd
)
It can be seen that it is based on specific parameters Construct a server The instance returned Choose one to have a look see BaseWSGIServer
# werkzeug/serving.py L708
class BaseWSGIServer(HTTPServer, object):
def __init__(
self,
host,
port,
app,
handler=None,
passthrough_errors=False,
ssl_context=None,
fd=None,
):
if handler is None:
# Notice here The specific processing of subsequent requests will go WSGIRequestHandler
handler = WSGIRequestHandler
# This way Port binding and listening
# And passed in the class WSGIRequestHandler
HTTPServer.__init__(self, server_address, handler)
# app namely flaks example
self.app = app
# In this method make_server Call immediately after returning the instance
def serve_forever(self):
self.shutdown_signal = False
try:
# Here HTTPServer be located python Built in Library http in http.server.HTTPServer
# Will the current server The instance is passed in as a parameter
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
finally:
self.server_close()
Looking down HTTPServer.serve_forever() You can find serve_forever In fact, it is the parent of its parent Built in Library socketserver in BaseServer Class implementation
# socketserver.py L153
class BaseServer:
timeout = None
def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
# This property is WSGIRequestHandler
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
# It's an infinite loop Receive a request and process a request
while not self.__shutdown_request:
ready = selector.select(poll_interval)
# bpo-35017: shutdown() called during select(), exit immediately.
if self.__shutdown_request:
break
if ready:
# After receiving the specific request To deal with
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
def _handle_request_noblock(self):
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
# After receiving the specific request To deal with
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)
def process_request(self, request, client_address):
# After receiving the specific request To deal with
self.finish_request(request, client_address)
self.shutdown_request(request)
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
# Instantiate each time WSGIRequestHandler Request processing
# Watch out! The third parameter sets the current server Case introduction
self.RequestHandlerClass(request, client_address, self)
well Eventually The request is processed in WSGIRequestHandler Handled during instantiation
So let's see WSGIRequestHandler The code of
WSGIRequestHandler The initialization of actually follows the parent class of the parent class BaseRequestHandler Of __init__ Method
# socketserver.py 696
class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
# Specific treatment methods In fact, it is the implementation of the subclass of the call
self.handle()
finally:
self.finish()
def setup(self):
pass
def handle(self):
pass
def finish(self):
pass
# werkzeug/serving.py L163
class WSGIRequestHandler(BaseHTTPRequestHandler, object):
# The core method of processing requests
def run_wsgi(self):
# Classic here take http The content is converted to conform to wsgi Content of format Because there is a wsgi Of app ah
self.environ = environ = self.make_environ()
headers_set = []
headers_sent = []
# You look familiar call wsgi app One of the parameters of
def start_response(status, response_headers, exc_info=None):
if exc_info:
try:
if headers_sent:
reraise(*exc_info)
finally:
exc_info = None
elif headers_set:
raise AssertionError("Headers already set")
headers_set[:] = [status, response_headers]
return write
def execute(app):
# classical wsgi app call The return value can be iterated
# Here app yes flask example The instance can be called naturally because Flask Realized __call__ Method
application_iter = app(environ, start_response)
try:
# Perform this method Parameter is flask example
execute(self.server.app)
except (_ConnectionError, socket.timeout) as e:
self.connection_dropped(e, environ)
except Exception:
#...
# The last class called handle This is this.
def handle(self):
"""Handles a request ignoring dropped connections."""
try:
# Calling the handle
BaseHTTPRequestHandler.handle(self)
except (_ConnectionError, socket.timeout) as e:
self.connection_dropped(e)
except Exception as e:
if self.server.ssl_context is None or not is_ssl_error(e):
raise
if self.server.shutdown_signal:
self.initiate_shutdown()
# you 're right The following class calls this method again
def handle_one_request(self):
"""Handle a single HTTP request."""
self.raw_requestline = self.rfile.readline()
if not self.raw_requestline:
self.close_connection = 1
elif self.parse_request():
# Eventually Take this method
return self.run_wsgi()
# http/server.py 147
class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
# This is what the last class called
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = True
# Here we call back WSGIRequestHandler Of handle_one_request
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
The above call route looks a little around , Because it involves the coverage of inheritance methods , Some calls go to the parent class , Some methods of subclasses .
You can see : In fact, it is the listening port , And start an infinite cycle , After each request is received , Is instantiated WSGIRequestHandler To deal with , and WSGIRequestHandler Mainly done HTTP Format data to WSGI Data conversion , And then use WSGI Is called flask The instance performs actual logical processing and returns data .
So let's see Flask The instance supports the calling code .
# flask/app.py L103
class Flask(_PackageBoundObject):
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def wsgi_app(self, environ, start_response):
# important Create the context object of the current request flask.ctx.RequestContext object
# The request information has been processed here ( To obtain the endpoint and view_func_args)
ctx = self.request_context(environ)
error = None
try:
try:
# Stack the context of the current request (LocalStack)
# Here is Flask Implementation details of context Pass the context through sharing For the back view_func
ctx.push()
# Distribute and execute
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
# After the request is processed Clean up context Out of the stack
ctx.auto_pop(error)
def full_dispatch_request(self):
# hook
self.try_trigger_before_first_request_functions()
try:
# hook
request_started.send(self)
rv = self.preprocess_request()
if rv is None:
# The main method of executing logic
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)
def dispatch_request(self):
# Get the current request context directly from the context stack
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
# ...
# according to endpoint Get the corresponding view_func Execute and return
return self.view_functions[rule.endpoint](**req.view_args)
okk, hither Flask Starting the process is basically about the same .
Summarize the steps :
- Create a Flask example app
- take url and view_func adopt app.add_url_rule() Maintenance to app Of url_map and view_functions Properties of the .url_map Contains routing logic ,view_functions The corresponding logic function is stored , Both by endpoint Related to .
- step 1 and 2 After completion , In fact, one follows WSGI Agreed web application It's ready , The next thing we need to do is to attach it to the same support WSGI Agreed web server below .web server Accept HTTP Request for agreement , And turn it into WSGI Content of format , And then call app(environ, start_response) Perform specific logical processing , And back to WSGI Results in format . After that WSGI The result of format is converted to HTTP Just return the format to the client .
- werkzeug Medium BaseWSGIServer Inherited Python Built in library http.server.HTTPServer, From which HTTPServer The ability to listen to ports and get requests , And integrated app and WSGIRequestHandler. Whenever a request is ready , Just give it to one WSGIRequestHandler Case handling .WSGIRequestHandler Did HTTP Format data to WSGI Format conversion , And implement app(environ, start_response) , Return response .
- app(environ, start_response) This step goes back to flask Request processing logic , according to environ The information of has been bound in advance url_map, Get specific routing information and parameters (endpoint,view_func_args), And then from view_functions Take the corresponding... From the dictionary view_function Run and return results .
边栏推荐
- Modes of optical fiber - single mode and multimode
- Harmonyos practice - Introduction to development, analysis of atomized services
- 【日常训练--腾讯精选50】292. Nim 游戏
- Web architecture design process
- [daily training -- Tencent selected 50] 235 Nearest common ancestor of binary search tree
- 判断文件是否为DICOM文件
- win配置pm2开机自启node项目
- Polynomial locus of order 5
- SAP ABAP BDC(批量数据通信)-018
- SQLSTATE[HY000][1130] Host ‘host. docker. internal‘ is not allowed to connect to this MySQL server
猜你喜欢
Get the way to optimize the one-stop worktable of customer service
爬虫练习题(三)
Paper reading [semantic tag enlarged xlnv model for video captioning]
Pytorch builds neural network to predict temperature
消息队列:消息积压如何处理?
pytorch_ 01 automatic derivation mechanism
How to improve website weight
CVE-2021-3156 漏洞复现笔记
What is message queuing?
京东商品详情页API接口、京东商品销量API接口、京东商品列表API接口、京东APP详情API接口、京东详情API接口,京东SKU信息接口
随机推荐
【Shell】清理nohup.out文件
Randomly generate session_ id
R language [logic control] [mathematical operation]
404 not found service cannot be reached in SAP WebService test
分布式全局ID生成方案
Cve-2021-3156 vulnerability recurrence notes
WEB架构设计过程
Digital IC interview summary (interview experience sharing of large manufacturers)
Flink SQL realizes reading and writing redis and dynamically generates hset key
[daily training -- Tencent selected 50] 235 Nearest common ancestor of binary search tree
消息队列:重复消息如何处理?
Codeforces Round #416 (Div. 2) D. Vladik and Favorite Game
拼多多商品详情接口、拼多多商品基本信息、拼多多商品属性接口
SAP ABAP BDC(批量数据通信)-018
消息队列:消息积压如何处理?
5阶多项式轨迹
关于服装ERP,你知道多少?
Distributed global ID generation scheme
Sidecar mode
Flinksql 读写pgsql