Based on django runsever
- Entrance
- Execute python manage.py runserver
- 调用 django.core.management.commands.runserver.Command.handle
- 文件 runserver.py(django/core/management/commands/runserver.py)
- Execute python manage.py runserver
- Start TCP server
- From the above handle will enter django.core.servers.basehttp.run
# 其中 server_cls 为 WSGIServer 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: # 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 # wsgi_handler 为 settings.WSGI_APPLICATION 一般为 product_name/wsgi.py 中的 application httpd.set_app(wsgi_handler) # httpd_cls.application = application 在后面 get_app 方法中会获取到 httpd.serve_forever()
- From the above handle will enter django.core.servers.basehttp.run
- Enter server_forever
# socketserver.BaseServer.serve_forever
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
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:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
- Next, enter the self._handle_request_noblock ()
# socketserver.BaseServer._handle_request_noblock
def _handle_request_noblock(self):
"""Handle one request, without blocking.
I assume that selector.select() has returned that the socket is
readable before this function was called, so there should be no risk of
blocking in get_request().
"""
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)
Wherein the request, client_address = self.get_request (), which is just when a request socket object
# socketserver.TCPServer.get_request
def get_request(self):
"""Get the request and client address from the socket.
May be overridden.
"""
return self.socket.accept()
- Processing request self.process_request (request, client_address)
# socketserver.BaseServer.process_request
def process_request(self, request, client_address):
"""Call finish_request.
Overridden by ForkingMixIn and ThreadingMixIn.
"""
self.finish_request(request, client_address)
self.shutdown_request(request)
- Complete a request self.finish_request (request, client_address)
# socketserver.BaseServer.finish_request
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
Wherein RequestHandlerClass is WSGIRequestHandler (django.core.servers.basehttp.WSGIRequestHandler)
Note: This time the request is only a socket object <class 'socket.socket'>
- Instantiate handler socketserver.BaseRequestHandler
# socketserver.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()
Which self.handle
# django.core.servers.basehttp.WSGIRequestHandler.handle
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 (socket.error, AttributeError):
pass
- Self.handle_one_request obtain information from the request ()
# django.core.servers.basehttp.WSGIRequestHandler.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()) # 对应上面的 set_app
Wherein ServerHandler instantiation does not do special handling
# django.core.servers.basehttp.ServerHandler
pass
run
# wsgiref.handlers.BaseHandler.run
# application 则是上面的 get_app 拿到的结果
def run(self, application):
"""Invoke the application"""
# Note to self: don't move the close()! Asynchronous servers shouldn't
# call close() from finish_response(), so if you close() anywhere but
# the double-error branch here, you'll break asynchronous servers by
# prematurely closing. Async servers must return from 'run()' without
# closing if there might still be output to iterate over.
try:
self.setup_environ()
self.result = application(self.environ, self.start_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.
The call handler __call__
- The above application is actually a product / wsgi.py finally got the application is an example of WSGIHandler
# django.core.handlers.wsgi.WSGIHandler
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
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) # 发送 request_started 信号
request = self.request_class(environ) # 实例化 WSGIRequest 得到 django 中 view 中真实的 request
response = self.get_response(request) # 获取 response 会进入 middleware
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
- Examples of Request
# django.core.handlers.wsgi.WSGIRequest
pass
- Get response
# django.core.handlers.base.BaseHandler.get_response
def get_response(self, request):
"""Return an HttpResponse object for the given HttpRequest."""
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF)
response = self._middleware_chain(request)
response._closable_objects.append(request)
# If the exception handler returns a TemplateResponse that has not
# been rendered, force it to be rendered.
if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
response = response.render()
if response.status_code >= 400:
log_response(
'%s: %s', response.reason_phrase, request.path,
response=response,
request=request,
)
return response
Then back to run
- Attention to the next self.finish_response ()
# wsgiref.handlers.BaseHandler.finish_response
def finish_response(self):
"""Send any iterable data, then close self and the iterable
Subclasses intended for use in asynchronous servers will
want to redefine this method, such that it sets up callbacks
in the event loop to iterate over the data, and to call
'self.close()' once the response is finished.
"""
try:
if not self.result_is_file() or not self.sendfile():
for data in self.result:
self.write(data)
self.finish_content()
finally:
self.close()
# 其中 self.write
# wsgiref.handlers.BaseHandler.write
def write(self, data):
"""'write()' callable as specified by PEP 3333"""
assert type(data) is bytes, \
"write() argument must be a bytes instance"
if not self.status:
raise AssertionError("write() before start_response()")
elif not self.headers_sent:
# Before the first output, send the stored headers
self.bytes_sent = len(data) # make sure we know content-length
self.send_headers()
else:
self.bytes_sent += len(data)
# XXX check Content-Length and truncate if too many bytes written?
self._write(data)
self._flush()
# 其中 self._write
# wsgiref.handlers.SimpleHandler._write
def _write(self,data):
result = self.stdout.write(data)
if result is None or result == len(data):
return
from warnings import warn
warn("SimpleHandler.stdout.write() should not do partial writes",
DeprecationWarning)
while True:
data = data[result:]
if not data:
break
result = self.stdout.write(data)
# 其中 result = self.stdout.write(data)
def write(self, b):
self._sock.sendall(b)
with memoryview(b) as view:
return view.nbytes