当前位置:网站首页>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 .
边栏推荐
- pytorch_ 01 automatic derivation mechanism
- 基于NCF的多模块协同实例
- What EDA companies are there in China?
- 淘宝商品详情页API接口、淘宝商品列表API接口,淘宝商品销量API接口,淘宝APP详情API接口,淘宝详情API接口
- STM32按键状态机2——状态简化与增加长按功能
- Randomly generate session_ id
- [reading of the paper] a multi branch hybrid transformer network for channel terminal cell segmentation
- 架构设计的五个核心要素
- "Multimodal" concept
- Message queuing: how to ensure that messages are not lost
猜你喜欢
Paper reading [open book video captioning with retrieve copy generate network]
消息队列:如何确保消息不会丢失
Paper reading [semantic tag enlarged xlnv model for video captioning]
Forkjoin is the most comprehensive and detailed explanation (from principle design to use diagram)
上海字节面试问题及薪资福利
京东商品详情页API接口、京东商品销量API接口、京东商品列表API接口、京东APP详情API接口、京东详情API接口,京东SKU信息接口
Randomly generate session_ id
Message queue: how to deal with message backlog?
4. 对象映射 - Mapping.Mapster
OpenSergo 即将发布 v1alpha1,丰富全链路异构架构的服务治理能力
随机推荐
三级菜单数据实现,实现嵌套三级菜单数据
JVM the truth you need to know
Five core elements of architecture design
Opensergo is about to release v1alpha1, which will enrich the service governance capabilities of the full link heterogeneous architecture
分布式事务解决方案之TCC
R language [logic control] [mathematical operation]
谈fpga和asic的区别
数据中心为什么需要一套基础设施可视化管理系统
5. Data access - entityframework integration
Codeforces Round #416 (Div. 2) D. Vladik and Favorite Game
原生小程序 之 input切换 text与password类型
目标检测中的损失函数与正负样本分配:RetinaNet与Focal loss
[daily training -- Tencent selected 50] 235 Nearest common ancestor of binary search tree
集群、分布式、微服務的區別和介紹
Lombok plug-in
PowerPivot——DAX(函数)
淘宝商品详情页API接口、淘宝商品列表API接口,淘宝商品销量API接口,淘宝APP详情API接口,淘宝详情API接口
力扣102题:二叉树的层序遍历
消息队列:消息积压如何处理?
产业金融3.0:“疏通血管”的金融科技