【Django】源码解析django启动和访问过程(三)

Django访问过程(一)

前言

【Django】源码解析django启动和访问过程(二)中我们了解到Django实际就是以WSGIRequestHandler作为self.RequestHandlerClass,并设置self.application为一个WSGIHandler类,然后启动的socketserver.TCPServer服务。这篇我们以socketserver.BaseServer.serve_forever为入口,接着剖析Django的访问过程。

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.
        """
        # 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方法进行处理,下边继续对该方法进行解读。

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:
        	# 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’进行处理,下面继续进行解读

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处理,下面我们继续对它进行解读。

django.core.servers.basehttp.WSGIRequestHandler.init

	# 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’继续进行解读。

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())

django.core.servers.basehttp.ServerHandler.run

    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__接续对访问过程的源码进行解读。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值