当前位置:网站首页>Flask 1.1.4 werkzeug1.0.1 analyse du code source: processus de démarrage
Flask 1.1.4 werkzeug1.0.1 analyse du code source: processus de démarrage
2022-07-07 05:52:00 【Ingénieur】
Basé surQuickStartUn desdemoPour analyser
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
if __name__ == '__main__':
app.run()
@app.route(“/”) Est une fonction d'usine de décoration qui reçoit les paramètres,Renvoie un décorateur qui ferme un paramètre spécifique
# flask/app.py L1288
def route(self, rule, **options):
# Garniture d'enregistrement typique
def decorator(f):
endpoint = options.pop("endpoint", None)
# Cette méthodeurlInformation etview_func Inscrivez - vous àflaskDans l'exemple
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
La clé est self.add_url_rule(rule, endpoint, f, **options) Méthodes Le code suivant a été simplifié
# flask/app.py L1178
@setupmethod
def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
# Ici.endpoint Est un concept important Les détails suivants seront expliqués dans la section routage
# Inflask- Oui. url_mapEtview_functions Un lien important entre
# Chaque fois qu'une demande arrive Vas - y.url_map Recherche dans endpoint,args Et partir view_functions[endpoint](args) Obtenir les résultats
# Si ce n'est pas le cas, Par défautview_func.__name__
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint
methods = options.pop("methods", None)
# ...
# Ici url_rule_class C'est unFlaskPropriétés de la classe La valeur est: werkzeug.routing.Rule
# Donc voici la construction werkzeug.routing.Rule Objet
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options
# Construit ruleEnregistrer l'objet dans url_map Dans les propriétés de l'Instance
# url_map- Oui.werkzeug.routing.Map Objet
# flask La partie routage est en fait basée sur werkzeugCapacité de
self.url_map.add(rule)
if view_func is not None:
# ...
# endpointPourkeyVa correspondre àview_funcEnregistrer dans view_functionsDans les propriétés
# view_functions C'est ça. dict
self.view_functions[endpoint] = view_func
C'est simple.,add_url_rule Le rôle principal est Oui.ruleEtview_func L'information est tenue à jour jusqu'à flaskExemple de url_mapEtview_functionsDans les propriétés
ok,Poursuivre les recherches app.run() C'est là que commence le processus (app.run() Ça va commencer par un simple web Le serveur est utilisé pour le développement et les tests , L'environnement de production utilisera d'autres web server, Mais avec cette étude, il est possible de lancer le processus )
# flask/app.py L889
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
# ...
from werkzeug.serving import run_simple
try:
# Avec l'aide de werkzeug.serving.run_simple
# Notez le troisième paramètre Oui.flask Exemple transmis à run_simpleMéthodes
# Suivi web serverAppelleflask Traitement logique de l'Instance
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
Regarde. run_simpleCode, Passez à la recherche werkzeug Code source
# 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 Les paramètres correspondent à flaskExemple
def inner():
try:
fd = int(os.environ["WERKZEUG_SERVER_FD"])
except (LookupError, ValueError):
fd = None
# C'est la clé Créer unserverExemple
srv = make_server(
hostname,
port,
application,
threaded,
processes,
request_handler,
passthrough_errors,
ssl_context,
fd=fd,
)
if fd is None:
log_startup(srv.socket)
# Appelezweb serverExemple deserve_foreverMéthodes
srv.serve_forever()
if use_reloader:
#...
else:
inner()
Continue.,Regardez d'abord make_serverMéthodes
# 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
)
C'est basé sur des paramètres spécifiques Construire unserverRetour d'instance Choisissez - en un et regardez Regarde. 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:
# Notez ici que Les demandes subséquentes seront traitées en détail WSGIRequestHandler
handler = WSGIRequestHandler
# Par ici Liaison du port et écoute
# Et passer dans la classe WSGIRequestHandler
HTTPServer.__init__(self, server_address, handler)
# appC'est - à - dire:flaksExemple
self.app = app
# Cette méthode est utilisée dansmake_server Appelé immédiatement après le retour de l'Instance
def serve_forever(self):
self.shutdown_signal = False
try:
# Ici HTTPServer Situé àpythonBibliothèque intégréehttpMoyenne http.server.HTTPServer
# Va maintenantserverInstance passée comme paramètre
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
finally:
self.server_close()
En bas HTTPServer.serve_forever() On peut le découvrir. serve_forever En fait, c'est le parent de son parent Bibliothèque intégrée socketserverMoyenne BaseServer Méthode d'implémentation de classe
# 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
# Cette propriété est 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)
# C'est une boucle infinie Recevoir une demande traiter une demande
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:
# Après avoir reçu une demande spécifique Traitement
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:
# Après avoir reçu une demande spécifique Traitement
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):
# Après avoir reçu une demande spécifique Traitement
self.finish_request(request, client_address)
self.shutdown_request(request)
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
# Chaque fois qu'il est instantané WSGIRequestHandler Traitement des demandes
# Attention! Le troisième paramètre prend le courant serverInstance passée dans
self.RequestHandlerClass(request, client_address, self)
D'accord. Final final Le traitement de la demande a eu lieu le WSGIRequestHandler Traitement pendant l'Instanciation
Voyons voir. WSGIRequestHandlerCode pour
WSGIRequestHandler L'initialisation prend en fait la classe mère de la classe mère BaseRequestHandler De__init__Méthodes
# 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:
# Traitement spécifique En fait, c'est l'implémentation de la Sous - classe appelée
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):
# Approche de base du traitement des demandes
def run_wsgi(self):
# Classique ici Oui.http Le contenu est converti en conformité avec wsgiContenu du format Parce qu'il y a un wsgiDeappOh là là!
self.environ = environ = self.make_environ()
headers_set = []
headers_sent = []
# Ça te dit quelque chose? Appelezwsgi appUn des paramètres de
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):
# Classiquewsgi appAppelez La valeur de retour peut être itérative
# Iciapp- Oui.flaskExemple L'instance peut être appelée naturellement parce que FlaskC'est fait.__call__Méthodes
application_iter = app(environ, start_response)
try:
# Exécuter cette méthode Le paramètre estflaskExemple
execute(self.server.app)
except (_ConnectionError, socket.timeout) as e:
self.connection_dropped(e, environ)
except Exception:
#...
# Appelé par la classe précédente handleC'est ça
def handle(self):
"""Handles a request ignoring dropped connections."""
try:
# Appelé parenthandle
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()
# C'est vrai La classe suivante appelle à nouveau cette méthode
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():
# Final final On y va.
return self.run_wsgi()
# http/server.py 147
class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
# C'est ce que la classe précédente a appelé
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = True
# Encore une fois appelé ici WSGIRequestHandler De handle_one_request
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
La ligne d'appel ci - dessus semble un peu tordue , Parce qu'il s'agit d'une superposition des méthodes d'héritage , Certains appellent le parent , Il y a des sous - classes qui marchent .
Je vois.: En fait, c'est écouter le port , Et ouvre un cycle infini , Chaque fois qu'une demande est reçue ,Instancie justeWSGIRequestHandlerTraitement,EtWSGIRequestHandlerSurtout.HTTPFormat des données àWSGIConversion des données,Et utiliserWSGILa façon dontflask L'Instance effectue le traitement logique réel et renvoie les données .
Regarde ça.Flask L'Instance supporte le Code appelé .
# 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 Créer l'objet contextuel actuellement demandé flask.ctx.RequestContextObjet
# Les informations demandées ont été traitées ici (J'ai endpointEtview_func_args)
ctx = self.request_context(environ)
error = None
try:
try:
# Mettre le contexte de la requête actuelle sur la pile (LocalStack)
# IciFlask Détails de la mise en oeuvre du contexte Transmettre le contexte par le partage À l'arrière.view_func
ctx.push()
# Exécution de la distribution
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
# Une fois le traitement de la demande terminé Contexte de nettoyage Hors de la pile
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:
# Méthode principale d'exécution de la logique
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)
return self.finalize_request(rv)
def dispatch_request(self):
# Obtenir le contexte actuel de la demande directement à partir de la pile de contexte
req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule
# ...
# SelonendpointObtenir la correspondanceview_func Exécuter et retourner
return self.view_functions[rule.endpoint](**req.view_args)
okk,IciFlask Le processus de démarrage est presque terminé .
Résumez les étapes :
- Créer unFlaskExemple app
- Oui.urlEtview_func Adoption app.add_url_rule() EntretienappDeurl_mapEtview_functions Dans les propriétés.url_map Contient la logique de routage ,view_functions La fonction logique correspondante est stockée ,Par les deuxendpointCorrélation.
- Étapes1Et2 Une fois terminé, En fait, on suit WSGIAccord web applicationPrêt à, Tout ce qu'on va faire, c'est l'accrocher au même support WSGIAccordweb serverEn bas.web serverAcceptéHTTPDemande d'accord,Et le convertir enWSGIContenu du format,Puis appelez app(environ, start_response) Effectuer un traitement logique spécifique ,Et revenir àWSGIRésultats du format.Plus tardWSGI Le résultat du format est converti en HTTP Le format est retourné au client .
- werkzeug Dans BaseWSGIServer HéritéPythonDe la bibliothèque intégrée http.server.HTTPServer, J'en ai tiré HTTPServer Capacité d'écouter les ports et d'obtenir les demandes ,Et intégré appEt WSGIRequestHandler. Chaque fois qu'une demande est prête , Donne - le à un WSGIRequestHandlerTraitement des instances.WSGIRequestHandlerC'est fait.HTTPFormat des données àWSGIConversion du format,Et la mise en œuvreapp(environ, start_response) ,Retour à la réponse.
- app(environ, start_response) Cette étape revient à flask Logique de traitement des demandes pour ,Selonenviron Avec des informations déjà liées url_map, Obtenir des informations et des paramètres de routage spécifiques (endpoint,view_func_args),Et de view_functions Extraire la correspondance dans le Dictionnaire view_functionExécuter et retourner les résultats.
边栏推荐
- Win configuration PM2 boot auto start node project
- What is message queuing?
- What are the common message queues?
- Unity keeps the camera behind and above the player
- Mapbox Chinese map address
- linear regression
- Common skills and understanding of SQL optimization
- nodejs获取客户端ip
- 4. Object mapping Mapster
- On the difference between FPGA and ASIC
猜你喜欢
三级菜单数据实现,实现嵌套三级菜单数据
架构设计的五个核心要素
Pinduoduo product details interface, pinduoduo product basic information, pinduoduo product attribute interface
Add salt and pepper noise or Gaussian noise to the picture
Web architecture design process
Bat instruction processing details
Web authentication API compatible version information
分布式事务介绍
Paper reading [open book video captioning with retrieve copy generate network]
WEB架构设计过程
随机推荐
SAP webservice 测试出现404 Not found Service cannot be reached
What is dependency injection (DI)
4. Object mapping Mapster
EMMC print cqhci: timeout for tag 10 prompt analysis and solution
MySQL-CentOS7通过YUM安装MySQL
Go 语言的 Context 详解
Simple case of SSM framework
zabbix_ Get test database failed
Dynamic memory management
PTA 天梯赛练习题集 L2-003 月饼 测试点2,测试点3分析
Reptile exercises (III)
Cve-2021-3156 vulnerability recurrence notes
Reading the paper [sensor enlarged egocentric video captioning with dynamic modal attention]
Industrial Finance 3.0: financial technology of "dredging blood vessels"
Flask1.1.4 Werkzeug1.0.1 源码分析:启动流程
目标检测中的BBox 回归损失函数-L2,smooth L1,IoU,GIoU,DIoU,CIoU,Focal-EIoU,Alpha-IoU,SIoU
async / await
分布式事务解决方案之TCC
数据中心为什么需要一套基础设施可视化管理系统
消息队列:消息积压如何处理?