manage.py
是启动入口,在里面调用execute_from_command_line(sys.argv)
方法html
def execute_from_command_line(argv=None): """Run a ManagementUtility.""" utility = ManagementUtility(argv) utility.execute()
ManagementUtility
对象的execute()
方法django
def execute(self): try: subcommand = self.argv[1] except IndexError: subcommand = 'help' # Display help if no arguments were given. if subcommand == 'help': ... elif subcommand == 'version' or self.argv[1:] == ['--version']: ... elif self.argv[1:] in (['--help'], ['-h']): ... else: # 关键代码,传入的subcommand='runserver'时,进入else分支 # 调用fetch_command()返回command对象,再调用对象的run_from_argv方法 self.fetch_command(subcommand).run_from_argv(self.argv)
fetch_command()
方法cookie
def fetch_command(self, subcommand): ... # Get commands outside of try block to prevent swallowing exceptions # commands是一个字典,key是subcommand,value是该subsommand对应的类所在的包的名称 # 好比{'runserver': 'django.contrib.staticfiles, ...} commands = get_commands() try: # subcommand = "runserver" # app_name = "django.contrib.staticfiles" app_name = commands[subcommand] except KeyError: ... sys.exit(1) if isinstance(app_name, BaseCommand): klass = app_name else: # 关键代码 # 加载"django.contrib.staticfiles.management.commands.runserver"模块中的Command类, # 而且实例化该类,klass其实是一个Command类实例 klass = load_command_class(app_name, subcommand) return klass
klass
是一个django.contrib.staticfiles.management.commands.runserver
模块中的Command
类的实例对象,他的父类其实是django.core.management.commands.runserver
中的Command类。session
run_from_argv()
方法是klass
对象的顶级父类中的方法。该方法中最终会调用django.core.management.commands.runserver
的Command类的handle()
方法。多线程
def handle(self, *args, **options): ... # 传入参数开启服务 self.run(**options) def run(self, **options): """Run the server, using the autoreloader if needed.""" use_reloader = options['use_reloader'] # debug模式 if use_reloader: autoreload.main(self.inner_run, None, options) else: # 非debug模式,开启服务 self.inner_run(None, **options) def inner_run(self, *args, **options): ... try: # 1. 先实例化WSGIHandler,获得全局惟一的application对象,handler就是application handler = self.get_handler(*args, **options) # 2. 而后再开启服务server_cls是django本身重写的WSGIServer类,继承自wsgiref的WSGIServer, # 重写的不是关键方法,就当作是wsgiref的WSGIServer便可 run(self.addr, int(self.port), handler, ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls) except socket.error as e: ... os._exit(1) except KeyboardInterrupt: if shutdown_message: self.stdout.write(shutdown_message) sys.exit(0)
再看一下run()
方法,是一个独立的函数在django.core.servers.basehttp
模块中app
def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): server_address = (addr, port) # threading默认为True, if threading: # 动态建立一个支持多线程的WSGIServer类,父类为ThreadingMixIn和原始的WSGIServer 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()
其中WSGIServer
是Django本身定义的一个类,继承自wsgiref
模块的simple_server.WSGIServer
类,继承自标准库http.server
模块的HTTPServer
类,继承自标准库socketserver
模块的TCPServer
类框架
WSGIRequestHandler
是Django本身定义的一个类,继承自wsgiref
模块的simple_server.WSGIRequestHandler
类,它重写了父类的handle()方法
这个类被做为参数传入到WSGIServer
中,等到请求到来时,会触发WSGIRequestHandler
类的实例化,在它实例化时会触发handle()
方法的调用。socket
注:每来一个请求都会实例化一个
WSGIRequestHandler
对象出来,而后这个对象来处理这个请求。ide
来看一下django自定义的WSGIRequestHandler
这个类函数
class WSGIRequestHandler(simple_server.WSGIRequestHandler): protocol_version = 'HTTP/1.1' ... def get_environ(self): for k, v in self.headers.items(): if '_' in k: del self.headers[k] # 关键在于调用了父类的get_environ()方法,wsgiref模块中的WSGIRequestHandler类的get_eniron()方法构造了environ字典 return super().get_environ() # handle()方法在WSGIRequestHandler的__init__()方法中被调用 def handle(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_response对象就是这个handler handler = ServerHandler( self.rfile, self.wfile, self.get_stderr(), self.get_environ() ) handler.request_handler = self # backpointer for logging # 在run()方法是调用application(environ, start_reponse)的 handler.run(self.server.get_app())
ServerHandler
的父类是wsgiref模块的BaseHandler
,它的做用就是用来调用application(environ, start_response)
的,它在WSGIRequestHandler
的handle()
方法中被实例化,同时把WSGIRequestHandler
对象的实例属性rfile
,wfile
,environ
做为初始化参数传入,此时ServerHandler
对象也持有这三个属性。而后调用run(application)
来调用application
。
class BaseHandler: ... def run(self, application): """调用application""" try: self.setup_environ() # 调用application(),返回一个response对象,在django中是HTTPResponse类的实例对象,赋值给了实例属性result self.result = application(self.environ, self.start_response) # 处理response对象中的数据发送到客户端 self.finish_response() except: try: self.handle_error() except: # If we get an error handling an error, just give up already! self.close() raise # ...and let the actual server figure it out. def setup_environ(self): """Set up the environment for one request""" env = self.environ = self.os_environ.copy() self.add_cgi_vars() # 给environ字典添加其余的key:value,这些字段是PEP333要求必须添加的 env['wsgi.input'] = self.get_stdin() env['wsgi.errors'] = self.get_stderr() env['wsgi.version'] = self.wsgi_version env['wsgi.run_once'] = self.wsgi_run_once env['wsgi.url_scheme'] = self.get_scheme() env['wsgi.multithread'] = self.wsgi_multithread env['wsgi.multiprocess'] = self.wsgi_multiprocess ... def finish_response(self): """处理application返回的result,是一个可迭代的response对象""" try: if not self.result_is_file() or not self.sendfile(): # response是一个可迭代对象,实现了__iter__()方法,返回response中保存的数据内容,data是html内容,不包含请求头的内容 for data in self.result: self.write(data) self.finish_content() finally: self.close() def start_response(self, status, headers,exc_info=None): """'start_response()' callable as specified by PEP 3333""" ... self.status = status # 这个方法最重要的做用是把响应头信息封装在headers中,做为本身的实例属性保存起来 self.headers = self.headers_class(headers) ... return self.write def write(self, data): """'write()' callable as specified by PEP 3333""" ... if not self.status: ... # headers_sent初始值为False,用于标记响应头是否发送 elif not self.headers_sent: # Before the first output, send the stored headers self.bytes_sent = len(data) # make sure we know content-length # 1.先把响应状态行+响应头经过wfile.write()方法发送给客户端,wfile就是一个跟socket关联的输出IO流对象 self.send_headers() else: self.bytes_sent += len(data) # XXX check Content-Length and truncate if too many bytes written? # 2. 再把响应体data经过wfile.write()方法发送到客户端 self._write(data) # 这个方法没用 self._flush()
总结:
WSGIRequestHandler
的做用有三点:
socket
对象分别封装成rfile
和wfile
对象,他们都是带缓冲的IO流对象,用于接受和发送数据给客户端。get_environ()
方法,用来构造environ
字典handler()
方法,将BaseHandler
的子类实例化,同时传入rfile
,wfile
,environ
参数。ServerHandler
的做用有三点:
WSGIRequestHandler
对象的rfile
,wfile
,environ
做为初始化参数run(application)
来调用application(environ, start_response)
。finish_response()
来处理application(environ, start_response)
返回响应对象response
,迭代response
对象中存放的数据发送给客户端。实际上ServerHandler
对象write(data)
方法中进行了3次socket.sendall()
调用,分别是:
socket.sendall(status_line)
响应状态行socket.sendall(headers)
响应头socket.sendall(body)
响应体WSGIRequestHandler
经过本身的handle()
方法与ServerHandler
对象产生了关联。而ServerHandler
对象在本身的run(application)
方法中调用application(environ, start_response)
,而application(environ, start_response)
又是django框架处理请求的入口,整个django框架处理请求的逻辑就在application(environ, start_response)
内部去实现了。
application是一个WSGIHandler
类的实例化对象,application(environ, start_response)
调用其实是调用了该对象的__call__(environ, start_response)
方法。
class WSGIHandler(base.BaseHandler): # WSGIRequest类是django本身提供的请求类,实例化以后就是request对象 request_class = WSGIRequest def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 加载中间件实例到内存中,此时中间件实例的各类方法已经被包裹在 _get_response() 方法的先后了 self.load_middleware() def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) # 实例化WSGIRequest,获得request对象,request对象中此时并无session属性,而是在中间件加载后, # 请求进入session中间件时,在session中间件的process_request()方法中动态添加的session属性 request = self.request_class(environ) response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase) response_headers = list(response.items()) for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return response
application(environ, start_response)
返回的是一个HTTPResponse
类的实例对象response
。在上面的ServerHandler
的,run(appliction)
方法能够看到,response
被赋值给了ServerHandler
的实例属性result
,最后把这个response
中包含的数据发送给客户端。
start_response()
方法的做用,主要是将响应头信息headers封装在Header对象中,而后把这个Header对象做为start_response
方法的持有者,即ServerHandler
对象的一个属性,最后在发送数据到客户端时,调用ServerHandler
对象的write(data)
方法时,能直接取到本身的属性headers来发送响应头给客户端。