django的web server的源代码流程
Posted arrowxiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django的web server的源代码流程相关的知识,希望对你有一定的参考价值。
1 class WSGIServer(simple_server.WSGIServer): 2 """BaseHTTPServer that implements the Python WSGI protocol""" 3 4 request_queue_size = 10 5 6 def __init__(self, *args, ipv6=False, allow_reuse_address=True, **kwargs): 7 if ipv6: 8 self.address_family = socket.AF_INET6 9 self.allow_reuse_address = allow_reuse_address 10 super().__init__(*args, **kwargs) 11 12 def handle_error(self, request, client_address): 13 if is_broken_pipe_error(): 14 logger.info("- Broken pipe from %s ", client_address) 15 else: 16 super().handle_error(request, client_address) 17 18 class WSGIRequestHandler(simple_server.WSGIRequestHandler): 19 protocol_version = ‘HTTP/1.1‘ 20 21 def address_string(self): 22 # Short-circuit parent method to not call socket.getfqdn 23 return self.client_address[0] 24 25 def log_message(self, format, *args): 26 extra = { 27 ‘request‘: self.request, 28 ‘server_time‘: self.log_date_time_string(), 29 } 30 if args[1][0] == ‘4‘: 31 # 0x16 = Handshake, 0x03 = SSL 3.0 or TLS 1.x 32 if args[0].startswith(‘x16x03‘): 33 extra[‘status_code‘] = 500 34 logger.error( 35 "You‘re accessing the development server over HTTPS, but " 36 "it only supports HTTP. ", extra=extra, 37 ) 38 return 39 40 if args[1].isdigit() and len(args[1]) == 3: 41 status_code = int(args[1]) 42 extra[‘status_code‘] = status_code 43 44 if status_code >= 500: 45 level = logger.error 46 elif status_code >= 400: 47 level = logger.warning 48 else: 49 level = logger.info 50 else: 51 level = logger.info 52 53 level(format, *args, extra=extra) 54 55 def get_environ(self): 56 # Strip all headers with underscores in the name before constructing 57 # the WSGI environ. This prevents header-spoofing based on ambiguity 58 # between underscores and dashes both normalized to underscores in WSGI 59 # env vars. nginx and Apache 2.4+ both do this as well. 60 for k in self.headers: 61 if ‘_‘ in k: 62 del self.headers[k] 63 64 return super().get_environ() 65 66 def handle(self): 67 self.close_connection = True 68 self.handle_one_request() 69 while not self.close_connection: 70 self.handle_one_request() 71 try: 72 self.connection.shutdown(socket.SHUT_WR) 73 except (socket.error, AttributeError): 74 pass 75 76 def handle_one_request(self): 77 """Copy of WSGIRequestHandler.handle() but with different ServerHandler""" 78 self.raw_requestline = self.rfile.readline(65537) 79 if len(self.raw_requestline) > 65536: 80 self.requestline = ‘‘ 81 self.request_version = ‘‘ 82 self.command = ‘‘ 83 self.send_error(414) 84 return 85 86 if not self.parse_request(): # An error code has been sent, just exit 87 return 88 89 handler = ServerHandler( 90 self.rfile, self.wfile, self.get_stderr(), self.get_environ() 91 ) 92 handler.request_handler = self # backpointer for logging & connection closing 93 handler.run(self.server.get_app())
WSGIServer的父类是wsgiref.simple_server.WSGIServer, wsgiref.simple_server.WSGIServer的父类是http.server.HTTPServer,http.server.HTTPServer的父类是socketserver.TCPServer;
WSGIRequestHandler的父类是wsgiref.simple_server.WSGIRequestHandler,wsgiref.simple_server.WSGIRequestHandler的父类是http.server.BaseHTTPRequestHandler,
http.server.BaseHTTPRequestHandler的父类是socketserver.StreamRequestHandler,socketserver.StreamRequestHandler的父类是socketserver.BaseRequestHandler
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) 实例化WSGIserver if threading: # ThreadingMixIn.daemon_threads indicates how threads will behave on an # abrupt shutdown; like quitting the server by the user or restarting # by the auto-reloader. True means the server will not wait for thread # termination before it quits. This will make auto-reloader faster # and will prevent the need to kill the server manually if a thread # isn‘t terminating correctly. httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever() #这里调用TCPserver的父类BaseServer的serve_forever方法
在socketserver.BaseServer.serve_forever中
1 def serve_forever(self, poll_interval=0.5): 2 """Handle one request at a time until shutdown. 3 4 Polls for shutdown every poll_interval seconds. Ignores 5 self.timeout. If you need to do periodic tasks, do them in 6 another thread. 7 """ 8 self.__is_shut_down.clear() 9 try: 10 # XXX: Consider using another file descriptor or connecting to the 11 # socket to wake this up instead of polling. Polling reduces our 12 # responsiveness to a shutdown request and wastes cpu at all other 13 # times. 14 with _ServerSelector() as selector: 15 selector.register(self, selectors.EVENT_READ) 16 17 while not self.__shutdown_request: 18 ready = selector.select(poll_interval) 19 # bpo-35017: shutdown() called during select(), exit immediately. 20 if self.__shutdown_request: 21 break 22 if ready: 23 self._handle_request_noblock() 在这里调用process_request方法 24 25 self.service_actions() 26 finally: 27 self.__shutdown_request = False 28 self.__is_shut_down.set()
在process_request方法中调用finish_request方法去实例化WSGIRequestHandler
1 def process_request(self, request, client_address): 2 """Call finish_request. 3 4 Overridden by ForkingMixIn and ThreadingMixIn. 5 6 """ 7 self.finish_request(request, client_address) 8 self.shutdown_request(request)
在finish_request中实例化WSGIRequestHandler
def finish_request(self, request, client_address): """Finish one request by instantiating RequestHandlerClass.""" self.RequestHandlerClass(request, client_address, self) #这个self是WSGIserver实例化的对象
class BaseRequestHandler: #实例化WSGIRequestHandler必须先初始化BaseRequestHandler类 """Base class for request handler classes. This class is instantiated for each request to be handled. The constructor sets the instance variables request, client_address and server, and then calls the handle() method. To implement a specific service, all you need to do is to derive a class which defines a handle() method. The handle() method can find the request as self.request, the client address as self.client_address, and the server (in case it needs access to per-server information) as self.server. Since a separate instance is created for each request, the handle() method can define other arbitrary instance variables. """ def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() #这个类没有实现handle方法,所以需要我们自己去实现 finally: self.finish() def setup(self): pass def handle(self): pass def finish(self): pass class StreamRequestHandler(BaseRequestHandler): """Define self.rfile and self.wfile for stream sockets.""" # Default buffer sizes for rfile, wfile. # We default rfile to buffered because otherwise it could be # really slow for large data (a getc() call per byte); we make # wfile unbuffered because (a) often after a write() we want to # read and we need to flush the line; (b) big writes to unbuffered # files are typically optimized by stdio even when big reads # aren‘t. rbufsize = -1 wbufsize = 0 # A timeout to apply to the request socket, if not None. timeout = None # Disable nagle algorithm for this socket, if True. # Use only when wbufsize != 0, to avoid small packets. disable_nagle_algorithm = False def setup(self): self.connection = self.request if self.timeout is not None: self.connection.settimeout(self.timeout) if self.disable_nagle_algorithm: self.connection.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True) self.rfile = self.connection.makefile(‘rb‘, self.rbufsize) if self.wbufsize == 0: self.wfile = _SocketWriter(self.connection) else: self.wfile = self.connection.makefile(‘wb‘, self.wbufsize) def finish(self): if not self.wfile.closed: try: self.wfile.flush() except socket.error: # A final socket error may have occurred here, such as # the local error ECONNABORTED. pass self.wfile.close() self.rfile.close()
在handle方法中
1 class WSGIRequestHandler(BaseHTTPRequestHandler): 2 3 server_version = "WSGIServer/" + __version__ 4 5 def get_environ(self): 6 env = self.server.base_environ.copy() 7 env[‘SERVER_PROTOCOL‘] = self.request_version 8 env[‘SERVER_SOFTWARE‘] = self.server_version 9 env[‘REQUEST_METHOD‘] = self.command 10 if ‘?‘ in self.path: 11 path,query = self.path.split(‘?‘,1) 12 else: 13 path,query = self.path,‘‘ 14 15 env[‘PATH_INFO‘] = urllib.parse.unquote(path, ‘iso-8859-1‘) 16 env[‘QUERY_STRING‘] = query 17 18 host = self.address_string() 19 if host != self.client_address[0]: 20 env[‘REMOTE_HOST‘] = host 21 env[‘REMOTE_ADDR‘] = self.client_address[0] 22 23 if self.headers.get(‘content-type‘) is None: 24 env[‘CONTENT_TYPE‘] = self.headers.get_content_type() 25 else: 26 env[‘CONTENT_TYPE‘] = self.headers[‘content-type‘] 27 28 length = self.headers.get(‘content-length‘) 29 if length: 30 env[‘CONTENT_LENGTH‘] = length 31 32 for k, v in self.headers.items(): 33 k=k.replace(‘-‘,‘_‘).upper(); v=v.strip() 34 if k in env: 35 continue # skip content length, type,etc. 36 if ‘HTTP_‘+k in env: 37 env[‘HTTP_‘+k] += ‘,‘+v # comma-separate multiple headers 38 else: 39 env[‘HTTP_‘+k] = v 40 return env 41 42 def get_stderr(self): 43 return sys.stderr 44 45 def handle(self): 46 """Handle a single HTTP request""" 47 48 self.raw_requestline = self.rfile.readline(65537) #读取游览器发来的请求包文起始 49 if len(self.raw_requestline) > 65536: #判断数据长度是否大于65536 50 self.requestline = ‘‘ 51 self.request_version = ‘‘ 52 self.command = ‘‘ 53 self.send_error(414) #发送414错误 54 return 55 56 if not self.parse_request(): # An error code has been sent, just exit 57 return 58 59 handler = ServerHandler( 60 self.rfile, self.wfile, self.get_stderr(), self.get_environ() 61 ) #rfile相当于socket中的recv,wfile相当于socket中的send, get_atderr是系统的标准错误输出句柄, get_environ是先将下划线开头的头部字段删除,再调用父类的get_envrion方法将请求的头部字段加上HTTP_,再添加一些公共字段 62 handler.request_handler = self # backpointer for logging 63 handler.run(self.server.get_app())
在run中
1 def run(self, application): 2 """Invoke the application""" 3 # Note to self: don‘t move the close()! Asynchronous servers shouldn‘t 4 # call close() from finish_response(), so if you close() anywhere but 5 # the double-error branch here, you‘ll break asynchronous servers by 6 # prematurely closing. Async servers must return from ‘run()‘ without 7 # closing if there might still be output to iterate over. 8 try: 9 self.setup_environ() #设置环境,将系统环境拷贝,然后将传入的环境变量扩展进该环境内同时增加一些WSGI通用环境 10 self.result = application(self.environ, self.start_response)#设置完环境后开始执行我们传入的handler对象 11 self.finish_response() 12 except: 13 try: 14 self.handle_error() 15 except: 16 # If we get an error handling an error, just give up already! 17 self.close() 18 raise # ...and let the actual server figure it out.
也就是执行以下代码
1 class WSGIHandler(base.BaseHandler): 2 request_class = WSGIRequest 3 4 def __init__(self, *args, **kwargs): 5 super(WSGIHandler, self).__init__(*args, **kwargs) 6 self.load_middleware() 7 8 def __call__(self, environ, start_response): 9 set_script_prefix(get_script_name(environ)) 10 signals.request_started.send(sender=self.__class__, environ=environ) 11 request = self.request_class(environ) 12 response = self.get_response(request) 13 response._handler_class = self.__class__ 14 15 status = ‘%d %s‘ % (response.status_code, response.reason_phrase) 16 response_headers = [(str(k), str(v)) for k, v in response.items()] 17 for c in response.cookies.values(): 18 response_headers.append((str(‘Set-Cookie‘), str(c.output(header=‘‘)))) 19 start_response(force_str(status), response_headers) 20 if getattr(response, ‘file_to_stream‘, None) is not None and environ.get(‘wsgi.file_wrapper‘): 21 response = environ[‘wsgi.file_wrapper‘](response.file_to_stream) 22 return response
以上是关于django的web server的源代码流程的主要内容,如果未能解决你的问题,请参考以下文章