Maison >développement back-end >Tutoriel Python >Analyser le processus en cours d'exécution du code source Python Django
WSGI surveillera en permanence les demandes envoyées par le client
middleware pour analyse et vérification
url distribution et vérification# 🎜🎜#
Processed
Return
# 🎜 🎜#1. Démarrage
sera distribuée à différentes classes pour être traitée selon les paramètres de ligne de commande Dans manange.py execute_from_command_line (sys.argv) entre le code clé# 🎜🎜#
def main(): os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testDjango.settings') try: from django.core.management import execute_from_command_line except ImportError as exc: --- execute_from_command_line(sys.argv)2. Dans la fonction execute_from_command_line, instanciez sa classe
ManagementUtility
puis exécutez lautility.execute( ) fonction [2.1. Cette fonction est spécialement utilisée pour analyser des paramètres, tels que python manage.py runserver
, python manage.py help
2.2 Il sélectionnera la classe ou fonction à utiliser en analysant les
paramètres supplémentaires, et la classe ou fonction correspond Avec python manage.py runserver
、python manage.py help
2.2 其会通过分析额外添加的参数选择要使用的类或者函数,类或者函数对应着djangocoremanagementcommands里面的类
def execute_from_command_line(argv=None): utility = ManagementUtility(argv) utility.execute()
3.从self.fetch_command(subcommand).run_from_argv(self.argv)[约第413行]
3.1 self.fetch_command(subcommand),这个函数返回了runserver.Command对象(可以自行深入查看),之后执行该Command父类里面的run_from_argv函数
def execute(self): --- if subcommand == 'help': --- elif subcommand == 'version' or self.argv[1:] == ['--version']: sys.stdout.write(django.get_version() + '\n') elif self.argv[1:] in (['--help'], ['-h']): sys.stdout.write(self.main_help_text() + '\n') else: self.fetch_command(subcommand).run_from_argv(self.argv)
4.从run_from_argv函数self.execute(*args, **cmd_options)进入
4.1 当前类也有这个execute函数,但是由于继承关系(此时的self也指向Command类),子类如果已经存在该函数会覆盖执行,execute是在子类 Command类中(之后由于super还会到父类里面)[约第354行]
def run_from_argv(self, argv): self._called_from_command_line = True parser = self.create_parser(argv[0], argv[1]) options = parser.parse_args(argv[2:]) cmd_options = vars(options) args = cmd_options.pop('args', ()) handle_default_options(options) try: self.execute(*args, **cmd_options) except CommandError as e: ---
5.execute函数执行output = self.handle(*args, **options)[约第398行]跳进子类runserver.Command类的handle函数
5.1 此时位于Command类的父类里面的execute,因为super().execute(*args, **options) #继承下来父类
def handle(self, *args, **options): if not settings.DEBUG and not settings.ALLOWED_HOSTS: raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.') self.use_ipv6 = options['use_ipv6'] if self.use_ipv6 and not socket.has_ipv6: raise CommandError('Your Python does not support IPv6.') self._raw_ipv6 = False if not options['addrport']: --- else: --- if not self.addr: self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addr self._raw_ipv6 = self.use_ipv6 self.run(**options)
6.handle 函数最后一行,从 self.run(**options) 进入
def run(self, **options): use_reloader = options['use_reloader'] if use_reloader: autoreload.run_with_reloader(self.inner_run, **options) else: self.inner_run(None, **options)
7.从def inner_run(self, *args, **options)
再执行run函数
def inner_run(self, *args, **options): --- try: handler = self.get_handler(*args, **options) run(self.addr, int(self.port), handler, ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls) except OSError as e: ---
8.最后启动服务,此时跳到django.core.servers.basehttp.py的run函数
8.1 httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
这一步特别重要,其涉及到较长的继承关系,2.监听-4.1这一环节会介绍到
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): server_address = (addr, port) if threading: httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) else: httpd_cls = server_cls httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()
总结流程:
解析运行 python manage.py 所提供的参数,例如: help
加载所有的app
根据参数找到相对应的命令管理工具
检查端口、ipv4检测、ipv6检测、端口是否占用、线程检查
orm对象检查表是否创建
最后启动python Lib库中的WSGIServer
解释:WSGI开启后,不间断的监听外界的请求
快速阅读:下面写的比较麻烦,最快了解监听和到中间件前的经过就是去读 1 、12.1 和 13
1.runserver成功开启后,关键的一步是httpd.serve_forever()
,其使得进入监听即一个死循环
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): --- httpd.set_app(wsgi_handler) httpd.serve_forever()
2.在serve_forever()
函数里面执行,当ready有值时,表示有请求发来,然后进入self._handle_request_noblock()
def serve_forever(self, poll_interval=0.5): self.__is_shut_down.clear() try: with _ServerSelector() as selector: selector.register(self, selectors.EVENT_READ) while not self.__shutdown_request: ready = selector.select(poll_interval) if self.__shutdown_request: break if ready: self._handle_request_noblock() self.service_actions() ---
3.从self._handle_request_noblock()
正常请求将进入self.process_request(request, client_address)
djangocoremanagementcommands
def _handle_request_noblock(self): try: request, client_address = self.get_request() except OSError: return if self.verify_request(request, client_address): try: 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)#🎜🎜#3 De #🎜🎜#self.fetch_command(subcommand).run_from_argv(self.argv)#🎜🎜#[À propos de la 413ème ligne] #🎜🎜#3.1 #🎜🎜#self.fetch_command(subcommand)#🎜🎜#, cette fonction renvoie l'objet #🎜🎜#runserver.Command#🎜🎜# (vous pouvez le visualiser en profondeur par vous-même), puis l'exécuter la #🎜 🎜#Command#🎜🎜##🎜🎜#run_from_argv#🎜🎜#function dans la classe parent#🎜🎜#
def process_request(self, request, client_address): """Start a new thread to process the request.""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads if not t.daemon and self.block_on_close: if self._threads is None: self._threads = [] self._threads.append(t) t.start()#🎜🎜#4. self.execute #🎜🎜#(*args, **cmd_options) entre #🎜🎜#4.1 La classe actuelle a également cette fonction #🎜🎜#execute#🎜🎜#, mais en raison de la relation d'héritage (self à ce moment pointe également à la #🎜🎜#Command class #🎜🎜#), si la fonction existe déjà dans la sous-classe, elle écrasera l'exécution #🎜🎜#execute#🎜🎜# est dans la sous-classe #🎜🎜#Command class #🎜. 🎜# (plus tard à cause du super#🎜🎜# ira dans la classe parent #🎜🎜#) [à propos de la ligne 354] #🎜🎜#
def process_request_thread(self, request, client_address): """Same as in BaseServer but as a thread. In addition, exception handling is done here. """ try: self.finish_request(request, client_address) except Exception: self.handle_error(request, client_address) finally: self.shutdown_request(request)#🎜🎜##🎜🎜#5.execute#🎜🎜#Exécution de la fonction # 🎜🎜#output = self.handle(*args , **options)#🎜🎜#[À propos de la ligne 398] Accédez à la fonction #🎜🎜#handle de la sous-classe #🎜🎜#runserver.Command#🎜🎜##🎜 🎜##🎜🎜#5.1 en ce moment Le #🎜🎜#execute#🎜🎜# dans la classe parent de #🎜🎜#Command class#🎜🎜# est dû au fait que
super().execute(*args, * *options) #hérite de la classe parent
#🎜🎜#class BaseServer: timeout = None def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass self.__is_shut_down = threading.Event() self.__shutdown_request = False#🎜🎜##🎜🎜#6.handle#🎜🎜# La dernière ligne de la fonction, saisissez #🎜🎜#
def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self) # self.RequestHandlerClass等同于self.WSGIRequestHandler#🎜 à partir de #🎜 🎜#self.run(**options)#🎜🎜# 🎜#7. Depuis
def inner_run(self, *args, **options)
, exécutez #🎜🎜#run function#🎜🎜# #🎜🎜#class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish()#🎜🎜#8. Enfin, démarrez le service, passez à ce moment à la fonction d'exécution de #🎜🎜#django.core.servers.basehttp.py#🎜🎜##🎜🎜#8.1
httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), { })
Cette étape est particulièrement importante car elle implique une longue relation d'héritage #🎜🎜#2. le lien présentera le #🎜🎜#def handle(self): self.close_connection = True self.handle_one_request() while not self.close_connection: self.handle_one_request() try: self.connection.shutdown(socket.SHUT_WR) except (AttributeError, OSError): pass#🎜🎜# processus récapitulatif : #🎜🎜##🎜🎜##🎜🎜##🎜🎜# Analysez les paramètres fournis en exécutant python manage.py, par exemple : help#🎜🎜 ##🎜🎜##🎜🎜##🎜🎜##🎜🎜 #Charger toutes les applications#🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#Trouver le #🎜🎜#Outil de gestion des commandes correspondant selon les paramètres#🎜🎜##🎜🎜##🎜🎜# #🎜🎜##🎜🎜##🎜🎜#Vérifier le port#🎜🎜#, #🎜🎜#détection ipv4#🎜🎜#, #🎜🎜# Détection ipv6#🎜🎜#, #🎜🎜#Si le port est occupé#🎜 🎜#, #🎜🎜#Thread check#🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜 #orm#🎜🎜#La table de vérification des objets est créée#🎜🎜##🎜🎜 ##🎜🎜##🎜🎜#Enfin démarrer #🎜🎜#WSGIServer#🎜🎜##🎜🎜##🎜🎜##🎜🎜# #🎜🎜#2. Surveillance#🎜🎜##🎜 🎜#Explication : Une fois WSGI activé, il surveillera en permanence les demandes externes#🎜🎜##🎜🎜#Lecture rapide : Il est plus difficile d'écrire ci-dessous, le plus rapide façon de comprendre#🎜🎜#La surveillance et le processus avant d'atteindre le middleware#🎜🎜 #Il suffit de lire#🎜🎜#1, 12.1 et 13#🎜🎜##🎜🎜##🎜🎜#2.1 runserver (serveur de test)#🎜 🎜##🎜🎜#1. Une fois le runserver démarré avec succès, l'étape clé est
httpd.serve_forever()
, ce qui lui fait entrer #🎜🎜#listening#🎜🎜#, qui est un #. 🎜🎜# boucle infinie#🎜🎜##🎜🎜#def handle_one_request(self): """Copy of WSGIRequestHandler.handle() but with different ServerHandler""" self.raw_requestline = self.rfile.readline(65537) if len(self.raw_requestline) > 65536: self.requestline = '' self.request_version = '' self.command = '' self.send_error(414) return if not self.parse_request(): # An error code has been sent, just exit return handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging & connection closing handler.run(self.server.get_app())#🎜🎜#2. Inserve_forever(), lorsque #🎜🎜#ready#🎜🎜# a une valeur, cela signifie qu'une requête a été envoyée, puis entre
self._handle_request_noblock()
#🎜🎜 #def run(self, application): try: self.setup_environ() self.result = application(self.environ, self.start_response) self.finish_response() except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError): return except: ---#🎜🎜#3 Requêtes normales de
self._handle_request_noblock()
. entrera self.process_request(request, client_address)
#🎜🎜#def _handle_request_noblock(self): try: request, client_address = self.get_request() except OSError: return if self.verify_request(request, client_address): try: 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)
4.从self.process_request(request, client_address)
进入来到了ThreadingMixIn.process_request
4.1 此时,如果没有搞清楚此时的self是谁,就搞不明白为什么进入到ThreadingMixIn.process_request,而不是其它的process_request,这时候就关联到上面提到的httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
4.2 type的用法是动态的创建类,此时httpd_cls 是一个新类,里面分别继承了ThreadingMixIn和server_cls对应得WSGIServer,这时就不难理解为什么找的是ThreadingMixIn.process_request
def process_request(self, request, client_address): """Start a new thread to process the request.""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads if not t.daemon and self.block_on_close: if self._threads is None: self._threads = [] self._threads.append(t) t.start()
5.在def process_request(self, request, client_address)
里面的t = threading.Thread(target = self.process_request_thread,args = (request, client_address))
实际调用了self.process_request_thread
,但是等t.start()
才会真正执行
def process_request_thread(self, request, client_address): """Same as in BaseServer but as a thread. In addition, exception handling is done here. """ try: self.finish_request(request, client_address) except Exception: self.handle_error(request, client_address) finally: self.shutdown_request(request)
6.从def process_request_thread(self, request, client_address)
进入,self.finish_request(request, client_address)
,继续完成请求
6.1 这时候又需要回顾之前的代码,因为self.RequestHandlerClass
不是已经有的类,而是初始化的时候赋值,其值变为了某个类
6.2 这个过程就在1.启动-8里面的httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
,此时的httpd_cls是type动态创建的,继承了ThreadingMixIn和server_cls对应得WSGIServer,实例化时会执行def __init__
方法,其关键执行了self.RequestHandlerClass = RequestHandlerClass
class BaseServer: timeout = None def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass self.__is_shut_down = threading.Event() self.__shutdown_request = False
def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self) # self.RequestHandlerClass等同于self.WSGIRequestHandler
7.从self.RequestHandlerClass(request, client_address, self)
,即去WSGIRequestHandler类里面初始化,根据一层层继承关系,只要最老类BaseRequestHandler
有初始化方法
class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() finally: self.finish()
从def __init__(self, request, client_address, server):
进入self.handle()
8.1 此时的self.handle()
,根据继承关系,其就在最小子类WSGIRequestHandler
里面
def handle(self): self.close_connection = True self.handle_one_request() while not self.close_connection: self.handle_one_request() try: self.connection.shutdown(socket.SHUT_WR) except (AttributeError, OSError): pass
9.从def handle(self)
进入self.handle_one_request()
def handle_one_request(self): """Copy of WSGIRequestHandler.handle() but with different ServerHandler""" self.raw_requestline = self.rfile.readline(65537) if len(self.raw_requestline) > 65536: self.requestline = '' self.request_version = '' self.command = '' self.send_error(414) return if not self.parse_request(): # An error code has been sent, just exit return handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging & connection closing handler.run(self.server.get_app())
10.从def handle_one_request(self)
进入handler.run(self.server.get_app())
10.1 注意此时handler为ServerHandler实例化对象,run方法存在它的最大父类BaseHandler里面
10.2 此时handler.run(self.server.get_app())
执行了self.server.get_app()
,其返回django.contrib.staticfiles.handlers.StaticFilesHandler
,handler.run把其当参数传递了过去
def run(self, application): try: self.setup_environ() self.result = application(self.environ, self.start_response) self.finish_response() except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError): return except: ---
11.从def run(self, application)
进入self.result = application(self.environ, self.start_response)
,其中application是django.contrib.staticfiles.handlers.StaticFilesHandler
11.1 其中self.application已经初始化了是WSGIHandler
class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler): def __init__(self, application): self.application = application self.base_url = urlparse(self.get_base_url()) super().__init__() def __call__(self, environ, start_response): if not self._should_handle(get_path_info(environ)): return self.application(environ, start_response) return super().__call__(environ, start_response)
12.进入后执行def __call__(self, environ, start_response)
方法,进入return self.application(environ, start_response)
,此时self.application已经初始化了是WSGIHandler
12.1 request = self.request_class(environ)
获取到用户请求的url后面就开始配置runserver启动时候加载的url; response = self.get_response(request)
获取用户url对应的响应准备开始往视图转
def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) ---
13.进入response = self.get_response(request)
,结束,再下一步就要开始中间件的进行
def get_response(self, request): set_urlconf(settings.ROOT_URLCONF) response = self._middleware_chain(request) response._resource_closers.append(request.close) if response.status_code >= 400: log_response( '%s: %s', response.reason_phrase, request.path, response=response, request=request, ) return response
解释:中间件的执行需要联系着上面运行过程,这个过程是一个递归的过程,下面介绍的五个函数是中间件命名规则对应得内容
process_request():完成请求对象的创建,但用户访问的网址尚未与网站的路由地址匹配。
process_view():完成用户访问的网址与路由地址的匹配,但尚未执行视图函数。
process_exception():在执行视图函数的期间发生异常,比如代码异常,主动抛出404异常等。
process_response():完成视图函数的执行,但尚未将响应内容返回浏览器
process_template_response():默认不执行,在视图函数完成操作后调用,除非视图函数返回的response中有render方法(几乎不会用,可以忽略)
1.递归的进入阶段:循环进行下面的代码(此代码位置django\core\handlers\exception.py)
1.1 此处出现process_request()
和process_response()
@wraps(get_response) def inner(request): try: response = get_response(request) # 此进入循环 except Exception as exc: response = response_for_exception(request, exc) return response return inner
def __call__(self, request): # Exit out to async mode, if needed if asyncio.iscoroutinefunction(self.get_response): return self.__acall__(request) response = None if hasattr(self, 'process_request'): response = self.process_request(request) # 进行中间件的process_request步骤 response = response or self.get_response(request) # 此进入循环 if hasattr(self, 'process_response'): response = self.process_response(request, response) # 此是递归后执行的 return response
2.递归的结束准备回传:进行下面的代码(此代码位置django\core\handlers\base.py)
2.1 此处出现process_view()
、process_template_response()
和process_exception()
进入视图的关键函数:
callback, callback_args, callback_kwargs = self.resolve_request(request) # callback即对于视图函数url匹配到对应的view函数
for middleware_method in self._view_middleware_view_middleware里面放着所有的process_view()函数(初始化时加载的), process_view()正是在该代码下面的环节循环执行
response = wrapped_callback(request, *callback_args, **callback_kwargs) 回调函数传参,并返回试图函数响应。
沿着这个路径连续进入两次,就到了后面讲到的as_view里面(此内容是专门视图处理的前的关键步骤)
response = self.process_exception_by_middleware(e, request)对应process_exception()
self._template_response_middleware 循环加载模板中间件
def _get_response(self, request): response = None callback, callback_args, callback_kwargs = self.resolve_request(request) for middleware_method in self._view_middleware: response = middleware_method(request, callback, callback_args, callback_kwargs) if response: break if response is None: wrapped_callback = self.make_view_atomic(callback) # 找到视图函数 # If it is an asynchronous view, run it in a subthread. if asyncio.iscoroutinefunction(wrapped_callback): wrapped_callback = async_to_sync(wrapped_callback) try: response = wrapped_callback(request, *callback_args, **callback_kwargs) except Exception as e: response = self.process_exception_by_middleware(e, request) if response is None: raise self.check_response(response, callback) if hasattr(response, 'render') and callable(response.render): for middleware_method in self._template_response_middleware: response = middleware_method(request, response) self.check_response( response, middleware_method, name='%s.process_template_response' % ( middleware_method.__self__.__class__.__name__, ) ) try: response = response.render() except Exception as e: response = self.process_exception_by_middleware(e, request) if response is None: raise return response
3.递归的结束回传:循环进行下面的代码
@wraps(get_response) def inner(request): try: response = get_response(request) # 此进入循环 except Exception as exc: response = response_for_exception(request, exc) return response return inner
def __call__(self, request): # Exit out to async mode, if needed if asyncio.iscoroutinefunction(self.get_response): return self.__acall__(request) response = None if hasattr(self, 'process_request'): response = self.process_request(request) response = response or self.get_response(request) # 此进入循环 if hasattr(self, 'process_response'): response = self.process_response(request, response) # 进行中间件的process_response步骤 return response
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!