【Django】源码解析django启动和访问过程(二)中我们了解到Django实际就是以WSGIRequestHandler作为self.RequestHandlerClass,并设置self.application为一个WSGIHandler类,然后启动的socketserver.TCPServer服务。这篇我们以socketserver.BaseServer.serve_forever为入口,接着剖析Django的访问过程。
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.
"""
# threading.Event()
# wait(tiemout=NOne),会阻塞线程
# clear,设置标志为False,表示阻塞所有设置wait的线程
# set,设置标志为True,唤醒设置wait的线程
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.
# 这里selector=selectors.PollSelector
with _ServerSelector() as selector:
# 注册读事件
selector.register(self, selectors.EVENT_READ)
# 持续监听
while not self.__shutdown_request:
# 每隔poll_interval监听一次注册的事件
ready = selector.select(poll_interval)
# bpo-35017: shutdown() called during select(), exit immediately.
if self.__shutdown_request:
break
# 获取到事件后进入self._handle_request_noblock()
if ready:
self._handle_request_noblock()
# 一次监听结束后的操作,需要自己重构
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
通过上边代码解读,可以知道,django监听到用户访问行为后,交给了self._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:
# socketserver.BaseServer.get_request(self):return self.socket.accept()
# self.socket = socket.socket(self.address_family, self.socket_type)
# 此处获取到了socket监听到的socket信息和地址
request, client_address = self.get_request()
except OSError:
return
# 对信息进行初步校验,这里实际没有做任何操作,直接返回了True
if self.verify_request(request, client_address):
try:
# socketserver.ThreadingMixIn.process_request
# 此处开启一个线程,处理这次访问请求
self.process_request(request, client_address)
except Exception:
# 异常处理
self.handle_error(request, client_address)
# 关闭这次socket连接
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)
从上述代码知道,用户的访问请求交给了‘socketserver.ThreadingMixIn.process_request’进行处理,下面继续进行解读
class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread."""
# Decides how threads will act upon termination of the
# main process
daemon_threads = False
# If true, server_close() waits until all non-daemonic threads terminate.
block_on_close = True
# For non-daemonic threads, list of threading.Threading objects
# used by server_close() to wait for all threads completion.
_threads = None
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
In addition, exception handling is done here.
"""
try:
# socketserver.BaseServer.finish_request
'''
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
'''
# 进入到self.RequestHandlerClass,也就是WSGIRequestHandler的处理流程
self.finish_request(request, client_address)
except Exception:
# 异常处理
self.handle_error(request, client_address)
finally:
# 处理完成后,关闭socket连接
self.shutdown_request(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))
# False,主线程等待子线程结束
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)
# 启动线程
'''
start -> _bootstrap -> _bootstrap_inner > run -> process_request_thread -> finish_request -> WSGIRequestHandler
'''
t.start()
...
上述代码可知,请求内容被交给了
django.core.servers.basehttp.WSGIRequestHandler
处理,下面我们继续对它进行解读。
# socketserver.BaseRequestHandler.__init__
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
# django启动流程中提到的WSGIServer类实例对象
# httpd_cls = class WSGIServer(socketserver.ThreadingMixIn,WSGIServer):...
self.server = server
# socketserver.StreamRequestHandler.setup
# 进行socket套接字设置,创建socket关联的读写文件对象
self.setup()
try:
# 具体的请求内容处理
# django.core.servers.basehttp.WSGIRequestHandler.handle
self.handle()
finally:
# 关闭套接字关联的读写文件对象
self.finish()
上述了解到请求处理进入了’django.core.servers.basehttp.WSGIRequestHandler.handle’, 下面对‘django.core.servers.basehttp.WSGIRequestHandler’继续进行解读。
class WSGIRequestHandler(simple_server.WSGIRequestHandler):
...
def handle(self):
# 标记关闭连接
self.close_connection = True
# 处理请求内容
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
try:
# 端口socket连接, 访问流程处理结束
self.connection.shutdown(socket.SHUT_WR)
except (socket.error, AttributeError):
pass
def handle_one_request(self):
"""Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
# 读取到的socket套接字信息
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
# 进一步分析套接字信息,获得协议,版本,请求头,路径,方法等信息
# 如果解析到content_type=keep-alive, self.close_connection标记为False
if not self.parse_request(): # An error code has been sent, just exit
return
# 实例化ServerHandler
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging & connection closing
# 重点来了,这里有没有很熟悉,Django在启动TCPServer服务的时候有‘httpd.set_app(wsgi_handler)’
# 这里获取到了之前设置的self.application,也就是django的settings文件中设置的‘WSGI_APPLICATION’,
# 也就是‘django.core.handlers.wsgi.WSGIHandler’的实例化对象
# 然后run方法将封装好的的套接字信息和'wsgiref.handlers.BaseHandler.start_response'传递给‘WSGIHandler’的__call__方法进行处理。
handler.run(self.server.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.environ
self.setup_environ()
# 调用WSGIHandler.__call__
self.result = application(self.environ, self.start_response)
# 处理self.result,调用ServerHandler实例化时候传入的self.wfile讲响应结果返回给访问客户端
self.finish_response()
except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):
# We expect the client to close the connection abruptly from time
# to time.
return
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.
通过上面源码解读,我们知道了请求内容进入了django.core.handlers.wsgi.WSGIHandler.__call__进行处理。
下一篇,我们将从WSGIHandler.__call__接续对访问过程的源码进行解读。