当前位置:网站首页>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.
边栏推荐
- 【已解决】记一次EasyExcel的报错【读取xls文件时全表读不报错,指定sheet名读取报错】
- Mapbox Chinese map address
- zabbix_get测试数据库失败
- 随机生成session_id
- English grammar_ Noun possessive
- make makefile cmake qmake都是什么,有什么区别?
- SAP ABAP BDC(批量数据通信)-018
- 京东商品详情页API接口、京东商品销量API接口、京东商品列表API接口、京东APP详情API接口、京东详情API接口,京东SKU信息接口
- SQLSTATE[HY000][1130] Host ‘host. docker. internal‘ is not allowed to connect to this MySQL server
- async / await
猜你喜欢
京东商品详情页API接口、京东商品销量API接口、京东商品列表API接口、京东APP详情API接口、京东详情API接口,京东SKU信息接口
4. Object mapping Mapster
Message queue: how to deal with message backlog?
分布式全局ID生成方案
JD commodity details page API interface, JD commodity sales API interface, JD commodity list API interface, JD app details API interface, JD details API interface, JD SKU information interface
《2022中国低/无代码市场研究及选型评估报告》发布
JVM the truth you need to know
Differences and introduction of cluster, distributed and microservice
目标检测中的损失函数与正负样本分配:RetinaNet与Focal loss
AI face editor makes Lena smile
随机推荐
盘点国内有哪些EDA公司?
京东商品详情页API接口、京东商品销量API接口、京东商品列表API接口、京东APP详情API接口、京东详情API接口,京东SKU信息接口
C nullable type
《HarmonyOS实战—入门到开发,浅析原子化服务》
Taobao store release API interface (New), Taobao oauth2.0 store commodity API interface, Taobao commodity release API interface, Taobao commodity launch API interface, a complete set of launch store i
nodejs获取客户端ip
An example of multi module collaboration based on NCF
EMMC打印cqhci: timeout for tag 10提示分析与解决
"Multimodal" concept
How to get free traffic in pinduoduo new store and what links need to be optimized in order to effectively improve the free traffic in the store
分布式事务介绍
Things about data storage 2
Flinksql 读写pgsql
目标检测中的损失函数与正负样本分配:RetinaNet与Focal loss
上海字节面试问题及薪资福利
消息队列:消息积压如何处理?
Différenciation et introduction des services groupés, distribués et microservices
Taobao Commodity details page API interface, Taobao Commodity List API interface, Taobao Commodity sales API interface, Taobao app details API interface, Taobao details API interface
Nvisual network visualization
R language [logic control] [mathematical operation]