Django源码解读之启动请求/响应过程

Django源码解读之MIddleware(中间件)
主程序入口django\core\management\commands\runserver.py
1.inner_run()
2.run()
3.再执行socketserver.py BaseServerserve_forever()

#django\core\management\commands\runserver.py
def inner_run(self, *args, **options):
    ....
    try:
        handler = self.get_handler(*args, **options)
        run(self.addr, int(self.port), handler,
            ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
    except OSError as e:
           ....
# django\core\servers\basehttp.py         
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
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

    
# socketserver.py
class BaseServer:
    def serve_forever(self, poll_interval=0.5):
      
        self.__is_shut_down.clear()
        try:
            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()
# serve_forever self._handle_request_noblock() -> process_request

执行BaseServer._handle_request_noblock() -> BaseServer.process_request->BaseServerfinish_request

serve_forever self._handle_request_noblock() -> process_request->finish_request

def finish_request(self, request, client_address):
    """Finish one request by instantiating RequestHandlerClass."""
    self.RequestHandlerClass(request, client_address, self)

RequestHandlerClass 就是WSGIRequestHandler,将其实例化


wsgihandler.png

实例化是执行self.handle()self.finish()

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

执行的是子类的handle
1.WSGIRequestHandler.handle()
2.WSGIRequestHandler.handle_one_request()
3.BaseHandler.run()

# django.core.servers.basehttp.py
WSGIRequestHandler.handle()
WSGIRequestHandler.handle_one_request()

# application = self.server.get_app() = wsgi_handler = WSGIHandler()
   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 (AttributeError, OSError):
            pass

    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())
# ServerHandler(simple_server.ServerHandler)继承ServerHandler(SimpleHandler)继承SimpleHandler(BaseHandler)    
# python3.7.5\Lib\wsgiref\handlers.py(python标准库)
class BaseHandler:
    def run(self, application):
        try:
            self.setup_environ()
            self.result = application(self.environ, self.start_response) # application 就是WSGIRequestHandler

由上述self.result = application(self.environ, self.start_response)
最后还是执行 application 就是WSGIRequestHandler实例的__call__()方法
最终执行WSGIHandler的__call__()方法

  1. request = self.request_class(environ) # HttpRequest
  2. response = self.get_response(request) # HttpResponse 重点看这个执行函数,里面包含中间件的执行
  3. 执行的get_response里面的self._middleware_chain(request)
  4. _middleware_chain就是中间件链,最内层的方法就是_get_response()

代码如下

# django.core.handlers.wsgi.py
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) # 发送信号对应的connect回处理函数
        request = self.request_class(environ) # HttpRequest
        response = self.get_response(request) # HttpResponse 重点看这个执行函数,里面包含中间件的执行

        response._handler_class = self.__class__

        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
            # If `wsgi.file_wrapper` is used the WSGI server does not call
            # .close on the response, but on the file wrapper. Patch it to use
            # response.close instead which takes care of closing all files.
            response.file_to_stream.close = response.close
            response = environ['wsgi.file_wrapper'](response.file_to_stream, response.block_size)
        return 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._resource_closers.append(request.close)
        if response.status_code >= 400:
            log_response(
                '%s: %s', response.reason_phrase, request.path,
                response=response,
                request=request,
            )
        return response

    
 # 真个最核心的就是这个方法,该方法才是依据路由,匹配到视图函数,返回响应   
 def _get_response(self, request):
        """
        Resolve and call the view, then apply view, exception, and
        template_response middleware. This method is everything that happens
        inside the request/response middleware.
        """
        response = None
        callback, callback_args, callback_kwargs = self.resolve_request(request) # 依据请求路由返回视图函数arg,kwargs参数

        # Apply view middleware
        for middleware_method in self._view_middleware:
            response = middleware_method(request, callback, callback_args, callback_kwargs)
            if response:
                break

        if response is None:
            wrapped_callback = self.make_view_atomic(callback)
            # If it is an asynchronous view, run it in a subthread.
            if asyncio.iscoroutinefunction(wrapped_callback):
                wrapped_callback = async_to_sync(wrapped_callback)
            try:
                response = wrapped_callback(request, *callback_args, **callback_kwargs) # 调用视图函数,返回HTTPResponse对象
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise

        # Complain if the view returned None (a common error).
        self.check_response(response, callback)

        # If the response supports deferred rendering, apply template
        # response middleware and then render the response
        if hasattr(response, 'render') and callable(response.render):
            for middleware_method in self._template_response_middleware:
                response = middleware_method(request, response)
                # Complain if the template response middleware returned None (a common error).
                self.check_response(
                    response,
                    middleware_method,
                    name='%s.process_template_response' % (
                        middleware_method.__self__.__class__.__name__,
                    )
                )
            try:
                response = response.render()
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise
        return response

上述_get_response方法中通过resolve_request来匹配路由返回对应的视图函数和请求参数
最终response = wrapped_callback(request, *callback_args, **callback_kwargs)执行返回响应

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容