Django启动命令源码-入口(wsgi)

WSGI启动

基于django启动命令python manage.py runserver,在调用到Command中的**inner_run()**方法的时候创建了handler

# C:\pyenvs\mysite\Lib\site-packages\django\core\management\commands\runserver.py
class Command(BaseCommand):
	...
    def inner_run(self, *args, **options):
        ...
        try:
        	# self.get_handler返回了一个WSGI handler
            handler = self.get_handler(*args, **options)  # next step
            run(self.addr, int(self.port), handler,
                ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
        except OSError as e:
            ...
        except KeyboardInterrupt:
            if shutdown_message:
                self.stdout.write(shutdown_message)
            sys.exit(0)

接下来看看self.get_handler

def get_handler(self, *args, **options):
    """Return the default WSGI handler for the runner."""
    # options: {'verbosity': 1, 'settings': None, 'pythonpath': None, 'traceback': False, 'no_color': False, 'force_color': False, 'addrport': None, 'use_ipv6': False, 'use_threading': True, 'use_reloader': True, 'use_static_handler': True, 'insecure_serving': False}
    return get_internal_wsgi_application()  # next step


    # 调用的basehttp模块中的get_internal_wsgi_application方法
    # C:\pyenvs\mysite\Lib\site-packages\django\core\servers\basehttp.py
	def get_internal_wsgi_application():

	# settings: <Settings "mysite.settings">
	# app_path: 'mysite.wsgi.application'
    from django.conf import settings
    app_path = getattr(settings, 'WSGI_APPLICATION')
    if app_path is None:
        return get_wsgi_application()

    # C:\pyenvs\mysite\Lib\site-packages\django\core\wsgi.py
    def get_wsgi_application():
    ...
    django.setup(set_prefix=False)
    return WSGIHandler()

	>self.get_handler()返回了一个WSGI可调用对象。避免了django.core.handler.WSGIHandler成为公共API,以防内部WSGI实现在未来发生变化或移动

接下来继续回到Command(BaseCommand)中的inner_run()方法,在get_handler()方法获取到一个WSGI handler之后,执行了run方法

class Command(BaseCommand):
    help = "Starts a lightweight Web server for development."

    # Validation is called explicitly each time the server is reloaded.
    requires_system_checks = []
    stealth_options = ('shutdown_message',)

    default_addr = '127.0.0.1'
    default_addr_ipv6 = '::1'
    default_port = '8000'
    protocol = 'http'
    # django自定义类,实现python WSGI协议的BaseHTTPServer
    # mro:WSGIServer>simple_server.WSGIServer>HTTPServer>socket.TCPServer>BaseServer
    server_cls = WSGIServer  

	def inner_run(self, *args, **options):
		try:
			# self.get_handler返回了一个WSGI handler
		    handler = self.get_handler(*args, **options)
		    # handler: <django.contrib.staticfiles.handlers.StaticFilesHandler object at 0x000002496F7DD388>
		    # server_cls是WSGIServer类的一个实例(封装了底层tcp)
		    run(self.addr, int(self.port), handler,
		        ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
		except OSError as e:
		    ...

接下来继续执行**run()**方法

# C:\pyenvs\mysite\Lib\site-packages\django\core\management\commands\runserver.py
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
	# server_address ('127.0.0.1', 8000)
    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) # next step
    ...
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

先看http_cls,其实就是WSGIServer类,接收了server_address, WSGIRequestHandler, ipv6=ipv6参数,最终返回了httpd

看看WSGIRequestHandler类是什么

# C:\pyenvs\mysite\Lib\site-packages\django\core\servers\basehttp.py
class WSGIRequestHandler(simple_server.WSGIRequestHandler):
	# django自定义的WSGIRequestHandler类的,继承自simple_server的WSGIReuquestHandler类
	# 声明了http协议的版本
    protocol_version = 'HTTP/1.1'

    ...

    def log_message(self, format, *args):
    	# 定义日志格式
    	...
        level(format, *args, extra=extra)

    def get_environ(self):
    	# 调用了父类的get_environ方法,wsgiref模块中的WSGIRequestHandler类的get_environ()方法构造了字典
        for k in self.headers:
            if '_' in k:
                del self.headers[k]

        return super().get_environ()

    # handle()方法在WSGIRequestHandler的__init__()方法中被调用
    '''
		class WSGIRequestHandler(BaseHTTPRequestHandler):
		    server_version: str
		    def get_environ(self) -> WSGIEnvironment: ...
		    def get_stderr(self) -> ErrorStream: ...
		    def handle(self) -> None: ...
    '''
    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

    def handle_one_request(self):
        """Copy of WSGIRequestHandler.handle() but with different ServerHandler"""

        # raw_requestline是客户端发来的请求行数据,读取请求行信息,其实这里读取的并不仅仅是请求行,而是
    	# 读取了65537字节的数据到rfile这个缓冲输入流中,在parse_request()方法中都会对这个raw_requestline
    	# 信息用"\r\n"来分割,取出第一行,也就是指取出请求行的信息。
        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

        # parse_request解析socket对象接收到http请求报文信息,赋值给自己的属性
        if not self.parse_request():  # An error code has been sent, just exit
            return
        # 实例化ServerHandler,django的WSGIHandler中传入的start_reponse对象就是这个handler
        handler = ServerHandler(
            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
        )
        handler.request_handler = self      # backpointer for logging & connection closing
        # 调用application(environ, start_reponse)
        handler.run(self.server.get_app())

django自定义WSGIRequestHandlerhandle_one_request方法中实例化ServerHandler,并调用了**run()**方法

看下ServerHandler是什么

 # C:\pyenvs\mysite\Lib\site-packages\django\core\servers\basehttp.py
    class ServerHandler(simple_server.ServerHandler):
    	http_version = '1.1'

	    def __init__(self, stdin, stdout, stderr, environ, **kwargs):
	        try:
	            content_length = int(environ.get('CONTENT_LENGTH'))
	        except (ValueError, TypeError):
	            content_length = 0
	        super().__init__(LimitedStream(stdin, content_length), stdout, stderr, environ, **kwargs)

	    def cleanup_headers(self):
	        super().cleanup_headers()
	        # HTTP/1.1 requires support for persistent connections. Send 'close' if
	        # the content length is unknown to prevent clients from reusing the
	        # connection.
	        if 'Content-Length' not in self.headers:
	            self.headers['Connection'] = 'close'
	        # Persistent connections require threading server.
	        elif not isinstance(self.request_handler.server, socketserver.ThreadingMixIn):
	            self.headers['Connection'] = 'close'
	        # Mark the connection for closing if it's set as such above or if the
	        # application sent the header.
	        if self.headers.get('Connection') == 'close':
	            self.request_handler.close_connection = True

	    def close(self):
	        self.get_stdin()._read_limited()
	        super().close()

	    def handle_error(self):
	        # Ignore broken pipe errors, otherwise pass on
	        if not is_broken_pipe_error():
	            super().handle_error()

WSGIServer:
django自定义的类,创建基于WSGI协议BaseHTTPServer
继承mro: WSGIServer>simple_server.WSGIServer>HTTPServer>socket.TCPServer>BaseServer

WSGIRequestHandler:

  1. 实例化socket对象封装成的rfile,wfile对象,(rfile,wfile都是带缓冲的IO流对象)。用于接收和发送数据给客户端
  2. 提供get_environ()来构造environ字典
  3. 实例化的时候调用自己重写的handler()方法,将BaseHandler的子类实例化。同时传入rfile, wfile, environ参数

ServerHandler,继承自BaseHandler:

  1. 实例化时,接受WSGIRequestHandler对象的rfile,wfile,environ作为初始化参数
  2. 调用自己的run(application)来调用application(environ, start_reponse)
  3. 调用自己的finsh_response()来处理application(environ, start_reponse)返回响应对象repoonse,迭代response对象中存放的数据发送给客户端

总结:

  1. Command执行inner_run方法
    def inner_run(self, *args, **options):
    	...
        handler = self.get_handler(*args, **options)
        run(self.addr, int(self.port), handler,
            ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
        ...
    
    1. 获取handler
      1. 调用get_handler方法获取handler, handler是一个WSGI handler
      2. get_handler方法调用get_internal_wsgi_application方法
      3. get_internal_wsgi_application方法返回WSGIHander()类实例
    2. 执行run方法
      1. run方法参数 self.server_cls: django自定义的WSGIServer类
      2. WSGIServer实现了WSGI协议的BaseHTPPServer
      3. WSGIServer的mro: WSGIServer>simple_server.WSGIServer>HTTPServer>socket.TCPServer>BaseServer
  2. 调用inner_run中的run()方法
    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()
    
    1. httpd_cls是WSGIServer类
    2. WSIGIServer接收参数WSGIRequestHandler参数
    3. WSGIRequestHandler是django自定义的类,重写父类handler()方法。作为参数传入WSGIServer类中
    4. 实例化的时候会把socket对象分别封装成rfile和wfile对象,他们都是带换成的io流对象,用于接收和发送数据给客户端

      rfile: 读取客户端的请求信息
      wfile: 写入响应并返回客户端
      IO流对象: 一般情况下是磁盘和内存之间输入输出

    5. 提供了get_environ(), 构造了environ字典
    6. 当有请求到来时候,就会触发WSGIRequestHandler类实例化,当它被实例化的时候触发handle()方法

      WSGIRequestHandler通过调用handle()与ServerHandler对象产生关联

      1. 当触发handle()方法时,handle方法实例化了ServerHandler()
      2. ServerHandler()实例化的接收了WSGIRequestHandler封装rfile, wfile对象以及environ作为初始化参数
      3. ServerHandler()调用内部的run(applicaion)来调用application(environ, start_reponse)
      4. application(environ, start_reponse)是dajngo框架处理请求的入口,请求处理逻辑就是application(environ, start_reponse)

        application是一个WSGIHandler类的实例化对象,application(environ, start_reponse)调用了该对象__call__(environ, start_reponse)

      5. 接着调用自己的finish_reponse()来处理application(environ, start_reponse)返回的reponse,迭代reponse返回给客户端
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值